diff --git a/Doc/library/socketserver.rst b/Doc/library/socketserver.rst index f1f87ea975ca42..e8d176edfcbda8 100644 --- a/Doc/library/socketserver.rst +++ b/Doc/library/socketserver.rst @@ -493,11 +493,17 @@ This is the server side:: def handle(self): # self.request is the TCP socket connected to the client - self.data = self.request.recv(1024).strip() - print("Received from {}:".format(self.client_address[0])) - print(self.data) + pieces = [b''] + total = 0 + while b'\n' not in pieces[-1] and total < 10_000: + pieces.append(self.request.recv(2000)) + total += len(pieces[-1]) + self.data = b''.join(pieces) + print(f"Received from {self.client_address[0]}:") + print(self.data.decode("utf-8")) # just send back the same data, but upper-cased self.request.sendall(self.data.upper()) + # after we return, the socket will be closed. if __name__ == "__main__": HOST, PORT = "localhost", 9999 @@ -514,20 +520,24 @@ objects that simplify communication by providing the standard file interface):: class MyTCPHandler(socketserver.StreamRequestHandler): def handle(self): - # self.rfile is a file-like object created by the handler; - # we can now use e.g. readline() instead of raw recv() calls - self.data = self.rfile.readline().strip() - print("{} wrote:".format(self.client_address[0])) - print(self.data) + # self.rfile is a file-like object created by the handler. + # We can now use e.g. readline() instead of raw recv() calls. + # We limit ourselves to 10000 bytes to avoid abuse by the sender. + self.data = self.rfile.readline(10000).rstrip() + print(f"{self.client_address[0]} wrote:") + print(self.data.decode("utf-8")) # Likewise, self.wfile is a file-like object used to write back # to the client self.wfile.write(self.data.upper()) The difference is that the ``readline()`` call in the second handler will call ``recv()`` multiple times until it encounters a newline character, while the -single ``recv()`` call in the first handler will just return what has been -received so far from the client's ``sendall()`` call (typically all of it, but -this is not guaranteed by the TCP protocol). +the first handler had to use a ``recv()`` loop to accumulate data until a +newline itself. If it had just used a single ``recv()`` without the loop it +would just have returned what has been received so far from the client. +TCP is stream based: data arrives in the order it was sent, but there no +correlation between client ``send()`` or ``sendall()`` calls and the number +of ``recv()`` calls on the server required to receive it. This is the client side:: @@ -542,13 +552,14 @@ This is the client side:: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: # Connect to server and send data sock.connect((HOST, PORT)) - sock.sendall(bytes(data + "\n", "utf-8")) + sock.sendall(bytes(data, "utf-8")) + sock.sendall(b"\n") # Receive data from the server and shut down received = str(sock.recv(1024), "utf-8") - print("Sent: {}".format(data)) - print("Received: {}".format(received)) + print("Sent: ", data) + print("Received:", received) The output of the example should look something like this: @@ -593,7 +604,7 @@ This is the server side:: def handle(self): data = self.request[0].strip() socket = self.request[1] - print("{} wrote:".format(self.client_address[0])) + print(f"{self.client_address[0]} wrote:") print(data) socket.sendto(data.upper(), self.client_address) @@ -618,8 +629,8 @@ This is the client side:: sock.sendto(bytes(data + "\n", "utf-8"), (HOST, PORT)) received = str(sock.recv(1024), "utf-8") - print("Sent: {}".format(data)) - print("Received: {}".format(received)) + print("Sent: ", data) + print("Received:", received) The output of the example should look exactly like for the TCP server example.