0

I was playing with python socket programming to understand them better and decided to use p2p communication. But there is a problem that I face.

You see I have two codes: peer1 and peer2. Both are quite straightforward and easy.

Peer1:

import socket
import time
from tqdm import tqdm

HOST = '127.0.0.1'
PORT_S = 9090
PORT_R = 8080

client_skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serv_skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

serv_skt.bind((HOST, PORT_R))
serv_skt.listen(1)

for i in tqdm(range(5), desc = 'You have 5 seconds to run the other peer program...'):
    time.sleep(1)


client_skt.connect((HOST,PORT_S))
# msg=client_skt.recv(1024)
# msg=msg.decode('utf-8')
# print(msg)

print("waiting for a friend...")
connection, address = serv_skt.accept()

welcome_message = "Welcome to " + HOST + " at " + str(PORT_R)

welcome_message = welcome_message.encode('utf-8')
connection.send(welcome_message)

print("Connection successful: connected to ", address)

while True:
    msg=input("Enter your message: \n")
    msg=msg.encode("utf-8")
    client_skt.sendall(msg)
    data = connection.recv(1024).decode('utf-8')
    if not data: break
    print("Recieved: ", data)

Exactly same for peer2 but with the ports interchanged:

Peer2:

import socket
import time
from tqdm import tqdm

HOST = '127.0.0.1'
PORT_R = 9090
PORT_S = 8080

serv_skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

serv_skt.bind((HOST, PORT_R))
serv_skt.listen(1)

for i in tqdm(range(5), desc = 'You have 5 seconds to run the other peer program...'):
    time.sleep(1)

client_skt.connect((HOST,PORT_S))
# msg=client_skt.recv(1024)
# msg=msg.decode('utf-8')
# print(msg)

print("waiting for a client...")
connection, address = serv_skt.accept()

welcome_message = "Welcome to " + HOST + " at " + str(PORT_R)

welcome_message = welcome_message.encode('utf-8')
connection.send(welcome_message)

print("Connection successful: connected to ", address)

while True:
    data = connection.recv(1024).decode('utf-8')
    if not data: break
    print("Recieved: ", data)
    msg=input("Enter your message: \n")
    msg=msg.encode("utf-8")
    client_skt.sendall(msg)
connection.close()

Most of you might have already guessed it: I can't run a client and a server at the same time, which throws me an error.

One way to counter this is to just sleep until the server binds. It works but it doesn't exit gracefully.

Q. Is there any alternate approach to this? Can one achieve p2p using sockets other than the approach mentioned above?

mayank
  • 176
  • 1
  • 12
  • 2
    What is it you are trying to achieve here? Two programs talking to each other? Something else? Is there a reason why one program cannot be the server and the other be the client? Why do you need to make both of them server and client? A client/server model will still allow bidirectional traffic. – Hannu Aug 30 '21 at 21:33
  • 1
    There are quite a many issues with these. If they both act as servers and clients, you will need threads to make sure the server component is always there waiting irrespective of what the client component does, and that server connections blocked in waiting for input do not block the client side. Just to get you started with something. – Hannu Aug 30 '21 at 21:36
  • 1
    You don't have a receive loop, see https://stackoverflow.com/a/43420503/238704 – President James K. Polk Aug 31 '21 at 00:21
  • Thanks, @Hannu! I thought we needed separate ports to create a peer, but from @(President James K. Polk)(thank you too) 's comment, it was further cemented that for two programs to talk to each other, we don't really need a separate port for a bidirectional exchange of strings... – mayank Aug 31 '21 at 04:19
  • 1
    You will get separate ports when you create client/server. When the server accepts the connection, accept returns the new port that you use in your receive loop to read data. The fixed server port is only used to connect but never to transmit data. All data transmissions happen between randomly created ports but the socket layer manages this for you. – Hannu Aug 31 '21 at 13:57
  • 1
    And this is why you need a threaded receive loop. As soon as you accept a connection, you fire a thread that starts receiving from the socket returned by accept. When the connection is closed, your thread can exit. Your main loop (sometimes called the accept loop) just returns to waiting for new connections immediately so that your server is not blocked by a single client talking to it. – Hannu Aug 31 '21 at 14:00
  • 1
    And that's not the only thing that is wrong with your code. With TCP sockets you will never know what you will receive as it is just a stream of data, not a deliverer of messages. If you send messages, you can receive just one message, several messages, a partial message or several complete and one partial message on one read, and your receiver must handle all these cases. You just receive whatever happens to be in the buffer when your client decides to read. You can use ZeroMQ if you want to simplify this - it looks very socket like but takes the abstraction level up and delivers messages. – Hannu Aug 31 '21 at 15:24

0 Answers0