3

I want to design a P2P network. This is a simplified program that explains my problem.

I want to ask is there a way to connect and accept connection simultaneously.

If not, do P2P networks use two ports, one to accept and other to connect.

I am using thread because I have to run sample of this program in all machines. That's why I'm taking input of host and port. On main thread it accepts connection and other connect.

The program below give me the following error:

socket.error: [Errno 106] Transport endpoint is already connected

import socket
from threading import Thread

s = socket.socket()
s.bind(('localhost', 6000))

def rec():
    s.listen(1)
    c, addr = s.accept()
    print 'Connection received from ' , addr

def test():
    host = raw_input("Enter Host address : ")
    port = input("Enter port : ")
    s.connect((host, port))
    print s.getsockname()[0]

def main():
     t = Thread(target=rec, args=())
     t.start()
     test()

if __name__ == '__main__':
    main()
Laschet Jain
  • 734
  • 1
  • 8
  • 24

1 Answers1

2

You can't listen and connect on the same socket. A listen socket can only be used to accept connections and a connection socket can only be a single bi-directional pipe. Further, if you try to do the same action such as send in multiple threads, you risk interleaving data. Your client should open its own socket, skip the bind and let the system assign the local connection port for you.

Since the created socket is bi-directional, a P2P app can communicate both ways and the choice of who does the connecting and who does the listening is based on other factors. You could, for instance, have both P2P machines listen so either side could start the conversation, but once its started, it runs on the bi-directional pipe.

zeromq is an interesting messaging system that can be used for P2P protocols. It has a very detailed description of various communication models and is well worth the read.

tdelaney
  • 73,364
  • 6
  • 83
  • 116
  • What do you mean by single bidirectional pipe? Can you please elaborate. – Laschet Jain Feb 14 '16 at 22:08
  • 1
    Suppose you have two machines h1 and h2. Once a connection has been made, h1's `send` ends up in h2's `recv` and vica-versa. It doesn't matter who started the conversation. Supposed you have a function `def my_p2p_conversation(connected_socket):...` that implements your protocol with sends and receives. It has a listen socket and if it receives a connection request, it runs the app (`my_p2p_connection(listen_socket.accept())`). If the user wants to initiate the connection, it does `my_p2p_connection(connection_socket.connect(('h2', 9876)))`. – tdelaney Feb 14 '16 at 22:40
  • 1
    That answer is misleading. You can obviously listen and connect on the same socket using, SO_REUSEADDR, SO_REUSEPORT options. In fact it's the only way to create P2P rendezvous connections. – user64204 Jul 19 '21 at 07:52
  • @user64204 - No, if you call `listen` on a socket you can't then call `connect` on the same socket, or visa-versa. A socket is an operating system construct. if you call listen, you get a socket that cannot be bound to a tcp endpoint but is instead used as an event source for connection requests coming in. If you call connect, you bind to a tcp endpoint for communcations. REUSEADDR and REUSEPORT don't have anything to do with it. Those are used to control what happens if you close a listening socket, open a new socket and attempt to bind to the same underlying address and port number. – tdelaney Jul 19 '21 at 17:25
  • You can. Just try it. Again that's how TCP NAT hole punching works. You do (bind, listen, accept) and (bind, connect) on the same local socket from two threads. Then one of them wins when the remote machine does the same. The second one fails. But that's ok. It fails only accept or connect when the socket is connected in second thread – user64204 Jul 28 '21 at 09:38
  • @user64204 A *program* can simultaneously listen to and connect from the same local port by using [the `SO_REUSEPORT`/`SO_REUSEADDR` flags](https://stackoverflow.com/q/14388706/1048572). However, the program will have to use two separate sockets for that - one socket can only either listen or connect, not both. – Bergi Sep 17 '22 at 21:37