Sockets and Network Connections
A socket is one end of a network connection and has an input stream for incoming data and an output stream for outgoing data.
A Natural Assumption About Sending
Imagine a program that sends a message through a network connection and then immediately moves on to its next task. It feels safe to assume the message is already on its way to the other computer. The send call returned, nothing went wrong, so the data must have left the machine. Many beginners reason exactly this way when they first write network code, and the reasoning feels sound until you look at what the socket is doing behind the method call.
What do you think happens?
When an output method on a socket returns, has the message already reached the other computer?
Reveal answer
Not necessarily. A returned output call means the data was placed in the socket's buffer and scheduled for transmission. It does not mean the data has reached the network, let alone the other computer.
The output method's job ends when its data is in the buffer. Separate lower-level software removes data from the front of the buffer and transmits it later, so whether the data has left the machine is a separate question.
The rest of this article tests that belief. You will follow one message through a connection, see where it waits along the way, and then learn exactly which part of the natural assumption was right and which part was not.
One Socket, Two Streams
A socket is one end of a network connection. Each socket has two streams attached to it: an input stream for reading data that arrives from the other side, and an output stream for writing data that should travel to the other side.
The two ends of a connection mirror each other. Whatever one end writes to its output stream shows up in the input stream of the other end once it has crossed the network. It helps to picture the connection not as a single pipe that both sides share, but as a pair of one-way channels. Writing happens on one channel and reading happens on the other, and each end of the connection reaches both channels through its own socket.
Tracing a Message Through the Connection
Follow one message from start to finish. Program A calls an output method on its socket's output stream. The program does not hand the bytes directly to the network. Instead, the bytes go into the socket's buffer. Later, lower-level software takes them off the front of the buffer and transmits them across the network. On the other side, the bytes arrive and become available in the receiving socket's input stream. Program B can then call an input method to take them.
Notice that the message passes through several stages, and the program that wrote it only controls the first one. The calling program's responsibility ends when the data is placed into the buffer. Everything after that belongs to the surrounding software and the network.
How the Socket Buffer Holds Data
A socket buffer is a block of memory that behaves like a queue of data waiting to be transmitted. A program's output method places its data at the back of the buffer, and separate lower-level software takes data off the front and sends it over the network.
The diagram shows the buffer as a queue. Data enters at the back when an output call succeeds, and it leaves from the front when lower-level software transmits it. The buffer is what sits between a program that writes at one speed and a network that transmits at another.
Two Reasons a Call Waits
A socket input or output method can block, which means the calling thread stops and waits before continuing. There are two situations that cause this, and they have different causes even though the effect on the thread is the same. The flowchart below shows the decision each call makes.
What the Waiting Thread Experiences
Blocking is a property of the calling thread's progress, not just of the method itself. While a call is blocked, the thread does not continue executing the statements that follow the call. It stays in the waiting state until the condition clears: data arrives for an input call, or buffer space frees up for an output call. Then the method completes, returns, and the thread continues with the next statement.
Following a Full Buffer Step by Step
A Sender Outpacing the Network
Suppose a program writes messages to its socket in a tight loop, and the network transmits more slowly than the program writes. Trace what happens to the buffer and to the thread as the writes continue.
- 1Early writes
While the buffer has free room, each output call places its data at the back of the buffer and returns quickly. The thread keeps moving through the loop.
- 2Buffer fills
Lower-level software takes data off the front more slowly than the program adds data at the back, so the number of waiting messages grows.
- 3Next write blocks
When the buffer is full, the next output call cannot place its data anywhere. The output method blocks and the thread waits at that line.
- 4Space frees up
As lower-level software removes data from the front and sends it, space opens in the buffer. The waiting output call can then place its data and return, and the loop continues.
The thread is only held up when the buffer has no room. Between those moments, each returned output call still means only that the data is in the buffer, not that it has reached the other computer.
Mistakes When Reading Socket Calls
Common mistake Assuming a returned output call means the other computer has received the data
What it looks likeA program sends a message, then immediately assumes the peer has already processed it and proceeds on that basis.
Why it failsA returned output call means the data was placed in the socket's buffer and scheduled for transmission. The data may still be waiting in the buffer.
Do this insteadTreat a returned output call as confirmation that the data entered the buffer. Design any step that depends on the peer receiving the data around an explicit reply from the peer.
Common mistake Believing an input call always returns immediately
What it looks likeA program reads from a socket right after connecting, expecting a message that the other side has not yet sent.
Why it failsIf the data has not arrived, the input method cannot return a result and the calling thread blocks until data shows up.
Do this insteadExpect that an input call may wait, and plan the program's flow so that waiting is acceptable.
Common mistake Thinking an output call only blocks because of the network being slow
What it looks likeA program writes in a loop and is puzzled that a write sometimes pauses.
Why it failsAn output call blocks when the buffer is full, which is a shortage of buffer space. The cause is the buffer filling faster than data is removed, not only a single slow network event.
Do this insteadRecognize buffer space as the condition for output blocking, and recognize incoming data as the condition for input blocking.
Common mistake Confusing the input stream and output stream as a single shared channel
Predicting Socket Behavior
A program calls an input method on its socket, but the other side has not sent anything yet. Describe what the calling thread does, and say what has to change before the thread can continue.
Hints
- Recall the condition that causes an input call to wait.
- Think about whether the calling thread moves to the next statement while the call is still waiting.
- Ask what event releases the thread from the wait.
A program writes to its socket output stream, and the output call returns. A later message is lost because the connection drops before transmission. Explain why the earlier return did not guarantee delivery, using the buffer as part of your answer.
Hints
- Consider where the data was when the output call returned.
- Consider which software removes data from the buffer and transmits it.
Key Takeaways
- A socket is one end of a network connection, with an input stream for incoming data and an output stream for outgoing data. The two ends mirror each other, so what one end writes arrives in the other end's input stream.
- An input method blocks when the data it wants has not arrived yet. The calling thread waits and does not continue past the call until data shows up.
- An output method places its data in the socket's buffer and blocks only when the buffer is full. The calling thread waits until lower-level software frees space.
- A returned output call means the data was placed in the buffer and scheduled for transmission, not that it has reached the network or the other computer.