The same application over TCP (Transmission Control Protocol) Transmission Control Protocol The Internet transport protocol that delivers data reliably and in order, with flow control and congestion control. introduced in ch. 1 gains a connection — which means a handshake before anything moves, a second socket at the server, and eight packets where UDP (User Datagram Protocol) User Datagram Protocol A simple transport protocol with no reliability, no flow control and no congestion control. introduced in ch. 1 needed two.
Words you will meet
- SOCK_STREAM — the argument that makes a socket a TCP socket.
- Welcoming socket — the server socket whose only job is to listen for knocks.
- Connection socket — a fresh socket the server makes for one particular client.
connect()— the client call that triggers the three-way handshake.accept()— the server call that returns a new connection socket.listen()— puts the welcoming socket into listening state.
Why this matters
This is the last page of the chapter’s content, and it closes a loop that opened in section 2.1.4. That section listed what TCP offers and what it costs. This one shows both, in code you can run and in packets you can count.
The welcoming socket is also worth the attention the book gives it. The book says directly that students meeting TCP sockets for the first time confuse it with the connection socket. It is the one idea on this page a reader can carry away wrong without noticing.
What a connection changes
Unlike UDP (User Datagram Protocol) User Datagram Protocol A simple transport protocol with no reliability, no flow control and no congestion control. introduced in ch. 1 , TCP (Transmission Control Protocol) Transmission Control Protocol The Internet transport protocol that delivers data reliably and in order, with flow control and congestion control. introduced in ch. 1 is a connection-oriented connection-oriented service Simple The two sides greet each other and agree on state before any real data flows. Precise A service in which the client and server exchange transport-layer control information with each other before the application-level messages begin to flow. After this handshaking phase, a connection is said to exist between the sockets of the two processes; when the application finishes sending it must tear the connection down. introduced in ch. 2 — open in glossary protocol. Before client and server can send anything to each other, they first handshake handshaking Simple A short opening exchange that lets both sides get ready before the real data arrives. Precise The procedure by which a client and server exchange transport-layer control information before application-level messages flow. It alerts the client and server, allowing them to prepare for the packets to come. introduced in ch. 2 — open in glossary and establish a TCP connection.
One end of that connection is attached to the client socket and the other to a server socket. When it is created, the connection is associated with both socket addresses: the client’s IP (Internet Protocol) Internet Protocol The network-layer protocol that defines the datagram format and addressing every Internet device must use. introduced in ch. 1 address and port, and the server’s IP address and port.
In plain words — this is why send() takes no address
With the connection established, when one side wants to send data it just drops the data into the connection through its socket.
That is different from UDP, where the sending process had to attach a destination address to the packet before dropping it into the socket. Here the connection already knows where both ends are.
One fact, and it explains send() against sendto(), recv() against
recvfrom(), and the existence of connect() in the first place.
Knocking on the welcoming door
The client initiates contact, so the server must be ready. That means two things.
First, as with UDP, the server must be running as a process before the client attempts contact. Second, the server program must have a special socket that welcomes initial contact from a client process running on an arbitrary host.
Using the house-and-door analogy from section 2.1.2, the book calls the client’s first contact “knocking on the welcoming door”.
When the client creates its TCP socket it specifies the address of that welcoming socket — the server’s IP address and port number. It then initiates the three-way handshake.
The handshake is invisible to both programs
The three-way handshake, which takes place within the transport layer, is completely invisible to the client and server programs.
Neither program contains a line that constructs a SYN (synchronize) synchronize The TCP flag bit that marks a connection-establishment segment. Set in the first two segments of the three-way handshake (§3.5.6). introduced in ch. 3 , or waits for one, or acknowledges one. Hold on to that sentence — the capture at the end of this page shows those three packets existing anyway, and what they cost.
When the server hears the knocking, it creates a new
connection socket connection socket Simple A fresh socket the server creates for one particular client. Precise The new socket created in the server by accept(), dedicated to one particular client, through which that client’s bytes are read and the reply is written. Students meeting TCP sockets for the first time often confuse it with the welcoming socket.
introduced in ch. 2 — open in glossary
dedicated to that particular
client. In the code below the welcoming door is
serverSocket; the newly created socket dedicated to this client is
connectionSocket.
serverSocket is created, bound to port 12000, and put into listening state. It is the welcoming socket: the initial point of contact for every client that will ever connect. It carries no application data, now or ever.
Two clients arrive in turn. Watch which socket survives and which one does not.
Read all steps as text
- Before anyone arrives — serverSocket is created, bound to port 12000, and put into listening state. It is the welcoming socket: the initial point of contact for every client that will ever connect. It carries no application data, now or ever.
- Client A knocks — The client’s connect() triggers the three-way handshake. When the server “hears” the knocking, accept() returns a NEW socket — connectionSocket — dedicated to this one client. serverSocket is untouched.
- Client A is served, and its socket is closed — The server reads the sentence, capitalises it, sends it back, and calls connectionSocket.close(). That ends this client’s conversation and nothing else. The loop returns to accept().
- Client B knocks — Because serverSocket is still open, another client can knock on the door and send the server a sentence to modify. accept() produces a second connection socket, entirely separate from the first.
In plain words
From the application’s perspective, the client’s socket and the server’s connection socket are directly connected by a pipe. The client can send arbitrary bytes into its socket, and TCP guarantees the server will receive every byte, in the order sent.
And just as people go in and out through the same door, the pipe runs both ways. The client both sends into and receives from its socket, and the server does the same with its connection socket.
TCPClient.py
The whole client
from socket import *
serverName = 'servername'
serverPort = 12000
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((serverName, serverPort))
sentence = input('Input lowercase sentence:')
clientSocket.send(sentence.encode())
modifiedSentence = clientSocket.recv(1024)
print('From Server: ', modifiedSentence.decode())
clientSocket.close()Only a few lines differ significantly from the UDP version, and each difference is the connection showing through.
| Line | What changed, and why |
|---|---|
socket(AF_INET, SOCK_STREAM) | SOCK_STREAM instead of SOCK_DGRAM — a TCP socket. As before, the client’s own port number is not specified; the operating system chooses it. |
clientSocket.connect((serverName, serverPort)) | New. The parameter is the address of the server side of the connection. After this line executes, the three-way handshake has been performed and a TCP connection exists. |
clientSocket.send(sentence.encode()) | Sends the sentence through the socket and into the connection. The program does not create a packet or attach a destination address, as the UDP version had to — it simply drops the bytes in. |
modifiedSentence = clientSocket.recv(1024) | Characters arriving from the server accumulate here. |
clientSocket.close() | Closes the socket, and with it the TCP connection. The book notes this causes TCP in the client to send a TCP message to TCP in the server — packet 7 in the capture below. |
A small inconsistency in the book
The code listing on book page 161 reads clientSocket.recv(1024). The
line-by-line walkthrough two pages later quotes the same line as
clientSocket.recv(2048).
Either works — the argument is only the maximum number of bytes to read at once, and this sentence is far shorter than both. The listing is the authoritative version, so this site uses 1024. Flagged because a reader comparing the two pages would otherwise think they had misread one of them.
TCPServer.py
The whole server
from socket import *
serverPort = 12000
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(('', serverPort))
serverSocket.listen(1)
print('The server is ready to receive')
while True:
connectionSocket, addr = serverSocket.accept()
sentence = connectionSocket.recv(1024).decode()
capitalizedSentence = sentence.upper()
connectionSocket.send(capitalizedSentence.encode())
connectionSocket.close()| Line | What it does |
|---|---|
socket(AF_INET, SOCK_STREAM) | Creates the socket that will become the welcoming socket welcoming socket Simple The server socket whose only job is to listen for new clients knocking. Precise In a TCP server, the socket that is the initial point of contact for all clients wanting to communicate with the server. It is created, bound to the server port and put into listening state. When a client knocks, accept() returns a separate connection socket dedicated to that client, and the welcoming socket goes back to listening. introduced in ch. 2 — open in glossary . |
serverSocket.bind(('', serverPort)) | Associates port 12000 with it, exactly as the UDP server did. |
serverSocket.listen(1) | New. Has the server listen for TCP connection requests. The parameter is the maximum number of queued connections — at least 1. |
connectionSocket, addr = serverSocket.accept() | When a client knocks on this door, accept() creates a new socket in the server, dedicated to that particular client. The client and server then complete the handshaking. |
recv(1024).decode() then .upper() | Read the sentence and capitalise it — the same work as before. |
connectionSocket.send(...) | The reply goes out over the connection socket, not the welcoming one. |
connectionSocket.close() | Closes this client’s socket. But serverSocket remains open, so another client can now knock on the door and send a sentence to modify. |
The confusion the book warns about
Students who are encountering TCP sockets for the first time sometimes confuse the welcoming socket … and each newly created server-side connection socket.
The test is simple. Which socket do the bytes cross? Always the connection socket. The welcoming socket produces connection sockets and does nothing else, for the entire life of the server.
The two versions, side by side
| UDP§2.7.1 | TCPthis section | |
|---|---|---|
| Socket type argument | ||
| Before any data moves | ||
| Sending a message | ||
| Receiving a message | ||
| Sockets at the server | ||
| What the server closes | ||
| What arrives | ||
| Packets for one exchange |
Cells marked ⓘ have a reason behind them — click to read it.
The same application, written twice. Every difference traces back to one fact. Click any ⓘ.
What the connection actually costs
Section 2.7.1 captured the UDP version of this application: two packets. Here is the TCP version of the same exchange.
| No. | Time | Source | Destination | Protocol | Length | Info |
|---|---|---|---|---|---|---|
| 1 | 0.000000 | 192.168.1.24 | 198.51.100.7 | TCP | 54 | 51874 → 12000 [SYN] Seq=0 Win=64240 Len=0 |
| 2 | 0.090400 | 198.51.100.7 | 192.168.1.24 | TCP | 54 | 12000 → 51874 [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0 |
| 3 | 0.180800 | 192.168.1.24 | 198.51.100.7 | TCP | 54 | 51874 → 12000 [ACK] Seq=1 Ack=1 Win=64240 Len=0 |
| 4 | 0.181100 | 192.168.1.24 | 198.51.100.7 | TCP | 72 | 51874 → 12000 [PSH, ACK] Seq=1 Ack=1 Len=18 |
| 5 | 0.271800 | 198.51.100.7 | 192.168.1.24 | TCP | 72 | 12000 → 51874 [PSH, ACK] Seq=1 Ack=19 Len=18 |
| 6 | 0.271900 | 198.51.100.7 | 192.168.1.24 | TCP | 54 | 12000 → 51874 [FIN, ACK] Seq=19 Ack=19 Len=0 |
| 7 | 0.362300 | 192.168.1.24 | 198.51.100.7 | TCP | 54 | 51874 → 12000 [FIN, ACK] Seq=19 Ack=20 Len=0 |
| 8 | 0.452700 | 198.51.100.7 | 192.168.1.24 | TCP | 54 | 12000 → 51874 [ACK] Seq=20 Ack=20 Len=0 |
Packet 1 — Packet 1 of 8. clientSocket.connect() produced this, and the client program has not yet sent a single byte of the sentence. The UDP version was already finished sending by now.
Protocol tree — click a field
The actual bytes
0000 aa bb cc 00 00 01 aa bb cc 00 00 11 08 00 45 00 ..............E.0010 00 28 1a 01 40 00 40 06 34 d4 c0 a8 01 18 c6 33 .(..@.@.4......30020 64 07 ca a2 2e e0 3f 8a 12 c0 00 00 00 00 50 02 d.....?.......P.0030 fa f0 7d 29 00 00 ..})..
TCPClient.py and TCPServer.py exchanging one sentence. Six of these eight packets carry no application data at all: three open the connection and three more close it.
Six of these eight packets carry no data
Three open the connection. Two carry the sentence and its reply. Three close it again.
Now look back at the box above, where the book said the handshake is completely invisible to the client and server programs. That is true of the programs and false of the network. Packets 1, 2 and 3 correspond to no line of code in either file. A full round-trip time passes before packet 4 carries the first byte of the sentence.
This is the cost section 2.2.2 measured for HTTP (HyperText Transfer Protocol) HyperText Transfer Protocol The application-layer protocol that requests and transfers Web documents. introduced in ch. 1 , seen from the other side. It is also why section 2.1.4 said developers of Internet telephony applications prefer UDP: for an exchange this short, the connection costs more packets than the conversation.
Running them yourself
Run the two programs in two separate hosts, then compare them with the UDP pair from section 2.7.1. Reading them side by side is worth more than reading either alone.
Then modify them. The book suggests trying the socket programming assignments at the end of this chapter and the next ones. They build a web server, a UDP pinger, a mail client and a web proxy from exactly these foundations.
Where this differs from the UDP version: if the server is not running, a TCP client fails immediately and loudly, because connect() gets no answer to its SYN. The UDP client in the same situation blocks forever with no indication that anything is wrong. That is not a quality-of-implementation difference — it is the connection existing, and being the thing that failed.
Check yourself
Check yourself
0 of 7 answered1.A TCP server ends up with two sockets. What is each one for?
2.`clientSocket.send(sentence.encode())` passes no address. How does the data know where to go?
3.predictCompare the two captures. The UDP version of this application was two packets. How many is the TCP version, and how many of those carry the sentence?
4.In the capture, packet 3 is an ACK carrying no data. What has been achieved by the time it arrives, and what has not?
5.The TCP server closes `connectionSocket` after each client but never closes `serverSocket`. Why the difference?
6.Three lines differ most between UDPClient.py and TCPClient.py. Which set is it?
7.The book says the three-way handshake is "completely invisible to the client and server programs". What does the capture show about that claim?
What to remember
- The client’s
connect()triggers a three-way handshake that is invisible to both programs — and costs a full round-trip time before any data moves. - The server has two kinds of socket. The welcoming socket is the initial point of contact for all clients, and never carries data.
accept()returns a connection socket dedicated to one client, and that is the one every byte crosses. - The same exchange is 2 packets over UDP and 8 over TCP. Six of the eight carry no application data at all.