53 lines
2.6 KiB
Markdown
53 lines
2.6 KiB
Markdown
---
|
|
category: technology
|
|
title: About Sockets
|
|
tags:
|
|
- networking
|
|
- linux
|
|
- programming
|
|
---
|
|
A 'socket' is an abstraction for a network connection. Each machine has a socket it is communicating with; from an application's perspective, sockets make it possible to treat a network connection like a file, and simply read()/write() on it.
|
|
|
|
|
|
|
|
Here is an overview of the lifecycle of a TCP socket:
|
|
|
|
Establishing a connection
|
|
|
|
An application on one system creates a socket and then calls bind(), listen(), and accept() -> this creates a socket in the LISTEN state. The socket will stay in the LISTEN state (and the accept() call will block) until an incoming connection is made on that port.
|
|
|
|
On another system, an application creates a socket and calls connect(), passing it the address of the first system. This creates a client-side socket, which starts in SYN_SENT.
|
|
|
|
Once these two sockets start talking, they go through a '3-way handshake' (transparent to the application) to establish some necessary metadata, and then both sockets change to the ESTABLISHED state.
|
|
|
|
|
|
Sending data
|
|
|
|
At this point the applications can simply read() and write() to the socket. Each application will read() what the other application write()s.
|
|
|
|
|
|
|
|
Shutting down the connection
|
|
|
|
When one side of the connection calls close() on its socket, it sends a packet telling the other end it is finished (a FIN packet), and the socket *that sent the FIN* changes to FIN_WAIT.
|
|
|
|
When a connection *receives* a FIN, it changes to the CLOSE_WAIT state.
|
|
|
|
When a socket in FIN_WAIT receives a FIN, it closes.
|
|
|
|
A socket in CLOSE_WAIT, by contrast, cannot close *until the application calls close() on the socket*. Once this happens, the system sends a FIN so that the remote end can finish closing, and the socket closes.
|
|
|
|
|
|
|
|
|
|
|
|
Now, from an application's perspective, all of these socket states are transparent; they are a kernel abstraction. The application just has a file descriptor that it is writing and reading on. So how do we detect when the other side has closed down the connection (i.e. that we are in CLOSE_WAIT)?
|
|
|
|
When you try to read() on a socket the other side has close()d, you get EOF (the end of file marker). It is considered correct programming to, at this point, do any necessary clean-up work and call close() on your own socket.
|
|
|
|
Otherwise you end up with sockets is CLOSE_WAIT.
|
|
|
|
In other words, if a socket is stuck in CLOSE_WAIT, it is necessarily a fault in the application - the application is failing to check for the connection closing, and thus never calls close().
|
|
|
|
This problem is common in applications that do nothing but write() to their sockets (they never read() so they never detect the EOF).
|