This classification is a convenient division of sockets that are used differently, and sockets that are used in this way are referred to by these names. That is. However, it is clear that the listening socket is in a different state (ie Passive mode) because it is certain that it cannot ** send a connection request ** (Error: Transport endpoint is already connected
).
Server side | Client side | Explanation | |
---|---|---|---|
listening socket | listen()Becomes this socket by executing. | ---- | You are listening to a specific port. Send connection requests to other listening sockets(connect()To do)It is not possible. It is also said that the socket is in passive mode or is a passive socket. |
connected socket | accept()This socket is passed in the return value of the function. | connect()Is executed, and it becomes this socket by being accepted on the server side. | Connected socket. sent,You can do recv etc. |
All sockets other than the above | listen()Socket before running | connect()Socket before being accepted by the server side | listen()Also connect()Is also possible. listen listen()In the case of bind()Is necessary. |
One line is at the same time (not a physics term). There are some that are not one line, but almost one line, but they are not one line for the sake of clarity.
Regarding the state, I checked the packet with Wireshark and guessed it, so there may be something wrong. There are various methods for cutting, so this is just an example. And, strictly speaking, the functions that disconnect the connection are shutdown
and close
. It seems that the name shutdown
is more realistic and the name close
is destroy
.
(https://stackoverflow.com/questions/409783/socket-shutdown-vs-socket-close)
The socket descriptor in the table,
On the server side, listening_sock = socket.socket ()
, connected_sock = listening_sock.accept ()
. However, the socket referenced by listening_sock
goes into the listening state afterlistening ()
. The reason why it is set to listening_sock
at the time of socket creation is that it is clear that after that,listen ()
is performed to become a listening socket.
On the client side, sock = socket.socket ()
.
Server-side functions | Explanation | Server side state | Client-side function | Explanation | Client side status | |
---|---|---|---|---|---|---|
socket.socket() | Generation of sockets for listening. | CLOSED | socket.socket() | Generating a socket for connection. | CLOSED | |
listening_sock.bind() | Naming the socket. | CLOSED | ---- | ---- | CLOSED | |
listening_sock.listen() | Here, the socket actually becomes a listening socket and starts listening. The OS accepts the connection request. | LISTENING | ---- | ---- | CLOSED | |
〃 | ---- | LISTENING | sock.connect() | Connect the socket directly to the specified address. | SYN SENT | |
〃 | ---- | SYN RECV | 〃 | ---- | SYN SENT | |
〃 | ---- | ESTABLISHED | 〃 | ---- | ESTABLISHED |
Server-side functions | Explanation | Server side state | Client-side function | Explanation | Client side status | |
---|---|---|---|---|---|---|
---- | ---- | ESTABLISHED | ---- | ---- | ESTABLISHED | |
listening_sock.accept() | Accept the connection request. | 〃 | ---- | ---- | 〃 | |
---- | ---- | 〃 | sock.sendall() | Send a message to the server. | 〃 | |
connected_sock.recv() | Receive client-side messages. | 〃 | ---- | ---- | 〃 | |
connected_sock.sendall() | Send back the message. | 〃 | ---- | ---- | 〃 | |
---- | ---- | 〃 | sock.recv() | Receive server-side messages. | 〃 |
Server-side functions | Explanation | Server side state | Client-side function | Explanation | Client side status | |
---|---|---|---|---|---|---|
---- | ---- | ESTABLISHED | ---- | ---- | ESTABLISHED | |
connected_sock.close() | Terminate the connection. Any processing below this for sock(recv, send)Can't do it either. | FIN-WAIT-1 | ---- | ---- | ESTABLISHED | |
〃 | ---- | FIN-WAIT-2 | ---- | ---- | CLOSE-WAIT | |
〃 | ---- | FIN-WAIT-2 | sock.close() | Terminate the connection. Any processing below this for sock(recv, send)Can't do it either. | LAST-ACK | |
〃 | ---- | TIME-WAIT | 〃 | ---- | ??????? | |
---- | ---- | CLOSED | ---- | ---- | CLOSED |
socket()
First, create a socket (which I intend to use only to accept connection requests, that is, a listening socket).
The file descriptor that represents (references) the created socket is returned.
>>> listening_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> listening_sock
<socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('0.0.0.0', 0)>
AF_INET
indicates that the communication uses IPv4, and SOCK_STREAM
indicates that the socket is a socket for connection-type communication (stream-type communication) such as TCP. (* And provide full-duplex communication)
You can see that the IP address or port number of <... laddr = ...>
is all 0, set this next.
bind()
Then assign an address to that socket descriptor (listening_sock).
>>> listening_sock.bind(('127.0.0.1', 8000))
>>> listening_sock
<socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8000)>
You can see that (ip address, port number) is set in <... laddr = ...>
.
listen()
The generated socket starts listening at this point. Originally, at this point, it is only listening and not accepting, but the OS accepts the client's connection request on behalf of the application (that is, connects instead) and adds it to the application's acceptance queue (queue) To go. The OS can accept connection requests on behalf of the application up to the number given by the backlog
argument. Once the connection is passed to the application (that is, the application accepts it), there is one free space in the accept queue. Then, when the connection request is accepted, a new connection is created between the client-side socket and the new listening socket-independent connected socket, the listening socket reboots for the next connection request, and again on the same port. Listen.
>>> listening_sock.listen(5)
In the case of this code, backlog
is 5, so the OS can accept connection requests from 5 client-side sockets and put them on the acceptance queue. Any further connection request will result in an error.
accept()
When accept () is executed, the descriptor of the connected socket of the connection at the top of the queue accepts the incoming connection request if the OS accepts the connection request instead, otherwise it accepts the descriptor of the connected socket of that connection. return.
>>> connected_sock, client_address = listening_sock.accept()
In the above case, it accepts the connection request that comes to listening_sock, creates a new socket called connected_sock, and establishes a connection between that socket and the socket on the client side. (Neither listening_sock nor connected_sock is actually the socket itself) [Note]
I honestly don't know about this area. When [SYN] comes to the listening socket, will it send back [SYN, ACK] from the new socket to establish the connection? Or is there a concept of sockets at the level of the 3way handshake? In the first place, socket is an API that allows programmers to create communication programs optimized for the application without knowing the complicated parts of TCP (window control, flow control, retransmission control, etc.) and the parts below IP in detail. At the time of the 3way handshake, it may be that only the communication destination is determined by the address on the client side.
socket()
First, create a socket. Then the file descriptor that represents (references) the created socket is returned.
>>> listening_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> listening_sock
<socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('0.0.0.0', 0)>
connect()
Here, the connection request is actually sent to the listening socket (listening to the specified port) of the server.
>>> sock.connect(server_address)
sendall()
Send data.
recv()
Receive data.
close()
Release resources related to connection. (* Actually, you need to do shutdown () before this. Https://docs.python.org/ja/3/howto/sockets.html#disconnecting)
Recommended Posts