Reputation: 335
I implemented the Server-Client example in Python 3.5 from https://docs.python.org/3.5/library/socketserver.html. The Example works for the first message in the loop but the server sends always a FIN-Flag and i don't understand why.
server:
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
"""
The request handler class for our server.
It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def handle(self):
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
# just send back the same data, but upper-cased
self.request.sendall(self.data.upper())
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()
client:
import socket
import sys
import time
HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:])
# Create a socket (SOCK_STREAM means a TCP socket)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
# Connect to server and send data
sock.connect((HOST, PORT))
while True:
print("Try")
sock.sendall(bytes(data + "\n", "utf-8"))
# Receive data from the server and shut down
received = str(sock.recv(1024), "utf-8")
print("Sent: {}".format(data))
print("Received: {}".format(received))
time.sleep(5)
Wireshark:
17771 12:20:03.585705 127.0.0.1 127.0.0.1 59886 9999 TCP 52 59886 → distinct(9999) [SYN] Seq=0 Win=8192 Len=0 MSS=65495 WS=256 SACK_PERM=1
17772 12:20:03.585705 127.0.0.1 127.0.0.1 9999 59886 TCP 52 distinct(9999) → 59886 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=65495 WS=256 SACK_PERM=1
17773 12:20:03.585705 127.0.0.1 127.0.0.1 59886 9999 TCP 40 59886 → distinct(9999) [ACK] Seq=1 Ack=1 Win=8192 Len=0
17774 12:20:03.585705 127.0.0.1 127.0.0.1 59886 9999 TCP 49 59886 → distinct(9999) [PSH, ACK] Seq=1 Ack=1 Win=8192 Len=9
17775 12:20:03.585705 127.0.0.1 127.0.0.1 9999 59886 TCP 40 distinct(9999) → 59886 [ACK] Seq=1 Ack=10 Win=7936 Len=0
17776 12:20:03.585705 127.0.0.1 127.0.0.1 9999 59886 TCP 48 distinct(9999) → 59886 [PSH, ACK] Seq=1 Ack=10 Win=7936 Len=8
17777 12:20:03.585705 127.0.0.1 127.0.0.1 59886 9999 TCP 40 59886 → distinct(9999) [ACK] Seq=10 Ack=9 Win=7936 Len=0
17778 12:20:03.585705 127.0.0.1 127.0.0.1 9999 59886 TCP 48 distinct(9999) → 59886 [PSH, ACK] Seq=9 Ack=10 Win=7936 Len=8
17779 12:20:03.585705 127.0.0.1 127.0.0.1 59886 9999 TCP 40 59886 → distinct(9999) [ACK] Seq=10 Ack=17 Win=7936 Len=0
17780 12:20:03.585705 127.0.0.1 127.0.0.1 9999 59886 TCP 40 distinct(9999) → 59886 [FIN, ACK] Seq=17 Ack=10 Win=7936 Len=0
17781 12:20:03.585705 127.0.0.1 127.0.0.1 59886 9999 TCP 40 59886 → distinct(9999) [ACK] Seq=10 Ack=18 Win=7936 Len=0
17795 12:20:08.588160 127.0.0.1 127.0.0.1 59886 9999 TCP 40 59886 → distinct(9999) [FIN, ACK] Seq=10 Ack=18 Win=7936 Len=0
17796 12:20:08.588160 127.0.0.1 127.0.0.1 9999 59886 TCP 40 distinct(9999) → 59886 [ACK] Seq=18 Ack=11 Win=7936 Len=0
Upvotes: 0
Views: 1946
Reputation: 41116
It all lies in socketserver.py ([Python]: socketserver — A framework for network servers) and few other places: I'm going to use version 3.5.4 as a reference (doc quotes will be version 3 specific):
BaseServer.serve_forever(self, poll_interval=0.5)
(#215) calls _handle_request_noblock
(#234):
self._handle_request_noblock()
BaseServer._handle_request_noblock(self)
(#306) calls process_request
(#313):
self.process_request(request, client_address)
BaseServer.process_request(self, request, client_address)
(#335) calls shutdown_request
(#342):
self.shutdown_request(request)
TCPServer
extends BaseServer
(#370):
class TCPServer(BaseServer):
TCPServer
overrides shutdown_request
(#489):
def shutdown_request(self, request):
"""Called to shutdown and close an individual request."""
try:
#explicitly shutdown. socket.close() merely releases
#the socket and waits for GC to perform the actual close.
request.shutdown(socket.SHUT_WR)
except OSError:
pass #some platforms may raise ENOTCONN here
self.close_request(request)
request.shutdown(socket.SHUT_WR)
request
is a socket.socket
([Python]: Socket Objects) instancesocket.socket.shutdown
is defined in ${PYTHON_SRC_DIR}/Modules/socketmodule.c(#3986):
static PyObject *
sock_shutdown(PySocketSockObject *s, PyObject *arg)
{
int how;
int res;
how = _PyLong_AsInt(arg);
if (how == -1 && PyErr_Occurred())
return NULL;
Py_BEGIN_ALLOW_THREADS
res = shutdown(s->sock_fd, how);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
Py_INCREF(Py_None);
return Py_None;
}
As seen, it calls native shutdown
API:
According to the MSDN link above (didn't find official Ux related doc, but I can't say I tried very hard searching):
If the how parameter is SD_SEND, subsequent calls to the send function are disallowed. For TCP sockets, a FIN will be sent after all data is sent and acknowledged by the receiver.
Note (Ux <-> Win conversion): SHUT_* and SD_* corresponding constants have the same values (e.g. SHUT_WR = SD_SEND = 1)
Upvotes: 1