Background
I have a simple socket server setup that I am trying to allow simultaneous connections to and echo back the data. The client side launches several threads each making its own connection to the server. This works fine for the socket.send() call, but all subsequent calls cause either a "Connection reset by peer" or a "Broken pipe". Note that I have not found the change that toggles the reset and broken pipe. I have looked here on SO for a solution, but I'm afraid I may not know what to search for.
Am I going about this in the wrong manner, or am I overlooking something in my setup?
Server
import SocketServer
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
print "{} wrote: {}\n".format(self.client_address[0], self.data)
self.request.send(self.data.upper())
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
Client
import socket
import sys
import threading
import time
HOST, PORT = "localhost", 9999
def create_client():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
cur_thread = threading.current_thread()
sock.connect((HOST, PORT))
for x in range(55):
msg = "{}: {}\n".format(cur_thread.name, str(x))
# Connect to server and send data
print cur_thread.name + ": sending message\n"
sock.send(msg)
# Receive data from the server and shut down
received = sock.recv(2048)
print "RX:" + received
finally:
cur_thread = threading.current_thread()
response = "{}: Closing!\n".format(cur_thread.name)
print response
sock.close()
if __name__ == "__main__":
print "testing single thread"
#create_client()
print "starting threads"
client_1 = threading.Thread(target=create_client)
client_1.daemon = True
client_1.start()
client_2 = threading.Thread(target=create_client)
client_2.daemon = True
client_2.start()
time.sleep(20)
When you return from handle
the socket is closed. Use a while loop and return from handle
only when self.data == ''
. recv
returns zero bytes when the client closes the connection. Also don't strip()
the result until after testing the return value or you could get a false close. Finally, use ThreadingTCPServer
or the server can only handle one connection at a time.
Example:
import SocketServer
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
while True:
self.data = self.request.recv(1024)
if self.data == '':
break
self.data = self.data.strip()
print "{} wrote: {}\n".format(self.client_address[0], self.data)
self.request.send(self.data.upper())
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
server = SocketServer.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
Also note the send()
is not guaranteed to send all bytes of message, so use sendall()
or check the return value. recv()
can also be tricky. TCP/IP is a streaming protocol and has no concept of message boundaries, so it is up to you to implement a protocol to check that you have received a complete message. It is possible to send 10000 bytes and receive less than that, requiring multiple receives to get the whole message. It is also possible to make two sends and receive both in one receive, or even all of one send and part of another. For your example simply buffering all receives until there is a \n
in the message would do for a simple protocol.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With