1

I want to implement a simple two way communication between server and client using sockets. The Client sends messages and waits for replies. The Server reads messages and replies with appropriate results. I have the below codes, but both of them are hanging. Can you explain what is wrong here?

Server:

import socket
import time

HOST = "127.0.0.1"
PORT = 18735

# create socket and listen
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen()
print(f"Listening on {HOST}:{PORT}")

# accept connection
conn, addr = s.accept()
print(f"Accepted connection from {HOST}:{PORT}")

cmd = ""
while True:
    data = conn.recv(2)
    time.sleep(1)
    if not data:
        break
    print(data.decode())
    # conn.sendall(b"OK")  This line fixes the problem!

conn.sendall(b"Finished")
s.close()

Client:

import socket

HOST = "127.0.0.1"
PORT = 18735

# create socket and connect
cs = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cs.connect((HOST, PORT))

# send data
cs.sendall(b"123456")

# wait for a result
data = cs.recv(1024)
print("result: ", data)
cs.close()

EDIT: Now, I can solve the problem by sending the short message from the server. However, I wonder whether this is necessary or not?

torayeff
  • 9,296
  • 19
  • 69
  • 103
  • 1
    `data = conn.recv(2)` will block until data is received from the client or the client closes the connection (or some other network error). The server is waiting for this to happen but at the same time, the client is waiting for the server to send something. – 001 Sep 13 '21 at 12:36

1 Answers1

3

The server won't break out of its while loop until the client either disconnects or at least shuts down the write half of its connection (with cs.shutdown(socket.SHUT_WR)).

The client won't disconnect until it receives a message from the server, which the server sends outside of the while loop (i.e. after the client disconnects/shuts down the write half of its connection).

You've created a deadlock.

Fundamentally, the issue is that it doesn't make sense to wait until the client has disconnected before you send a response to that client. Either the client needs to not expect a response back, or the server needs to send it while the client is still connected. In the case of the latter, you probably need to implement one of the following:

  • The application protocol you're implementing needs a defined message structure so the server knows when the client has finished sending.
  • The client needs a special sequence it can send to indicate the end of a message.
  • The client needs to shut down the write half of its connection to indicate to the server that it won't send any more data.
Kemp
  • 3,467
  • 1
  • 18
  • 27
  • If you look on my edit, this problem can be easily solved by sending back some short message. However, I think it is redundant. – torayeff Sep 13 '21 at 12:33
  • Updated my answer to indicate a direction for the solution, but there's no simple fix I can give you that'll just work. – Kemp Sep 13 '21 at 12:41
  • Technically, the server won't break until the client **shuts down** the write end of it's connection. This can happen by the client calling `cs.shutdown(socket.SHUT_WR)` and still allow to the client to receive data send by the server afterward. – President James K. Polk Sep 13 '21 at 14:00
  • @PresidentJamesK.Polk True. I don't typically shut down only one direction myself so I didn't think of that. I'll update the answer to mention it. – Kemp Sep 13 '21 at 14:05