TheUnknownBlog

Back

If you’ve spent any time learning network programming in Go, you’ve likely marveled at how simple the net package is. With just three lines of code, you can create a performant TCP server. I mean

ln, _ := net.Listen("tcp", ":8080")
for {
    conn, _ := ln.Accept()
    go handle(conn)
}
go

But this simplicity often hides the mechanics. You know how to use net.Dial or net.Listen, but do you know what a “socket” actually is?

Here is what I learned about file descriptors, the OS kernel, and why your listener socket is “blind.”

The Socket is Just a File

In Unix-like operating systems (Linux, macOS), there is a golden rule: Everything is a file.

When you write this in Go:

conn, _ := net.Dial("tcp", "google.com:80")
go

You aren’t magically holding a physical wire connected to Google. You are asking the Operating System to create a network endpoint. The OS sets up the heavy lifting in memory and hands you back a simple integer, known as a File Descriptor. Yeah, just like anything else you read or write on your computer, a file on a disk, or stdin/stdout.

Your net.Conn object is essentially a wrapper around that number.

  • When you call conn.Write(), you are writing bytes to a file buffer.
  • When you call conn.Read(), you are reading bytes from a file buffer.
  • The OS kernel takes care of actually pushing that data across the physical wires.

Why Listeners Create New Sockets?

When I first try to write my SOCKS5 server with Go, the below case is the most confusing part. Look at this standard Go pattern:

ln, _ := net.Listen("tcp", ":8080")

for {
    conn, _ := ln.Accept()
    go handle(conn)
}
go

So why does ln.Accept() return a new connection (conn)? Why doesn’t it just use the ln object to talk to the client?

The Answer: Concurrency.

Think of your server as a busy hotel. If the Receptionist had to personally escort every guest to their room and stay there to chat, the front desk would be empty. No new guests could check in.

By design, the OS separates these roles. The Listener stays bound to Port 8080. When a Client arrives, the Listener performs the handshake, creates a new file descriptor for that specific conversation, and immediately goes back to watching the door for the next guest.

Same thing happens if you use C to create sockets. If your implement your server in C, you would go through slightly more steps: socket(), bind(), listen(), and then accept(). The accept() call is what creates a new socket file descriptor for the specific client connection.

int server_fd = socket(AF_INET, SOCK_STREAM, 0);
bind(server_fd, (struct sockaddr *)&address, sizeof(address));
listen(server_fd, 3);
int new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen);
c

The Listener is Blind

A common misconception is that because the Listener creates the connection, it must “see” all the traffic. But is it true? e.g. in the above C code, can you read data from server_fd? Is it possible to do something like this?

char buffer[1024] = {0};
read(server_fd, buffer, 1024); // Is this valid?
c

If you tried to read data from the listening socket, what would happen? It would fail. The listening socket is essentially blind to data payloads. It only understands one thing: The Handshake (SYN packets).

When a packet of data arrives at your server’s IP, the Operating System does the following:

  1. Is this a new handshake? Send it to the Listener.
  2. Is this data for an active conversation? Look up the specific Child Socket (that conn object you got earlier) and send the data there.

The Listener is just a forwarder for new connections. It doesn’t handle data itself.

Why This Matters?

Understanding that Accept() generates a new, independent file descriptor is exactly why Go is so good at networking.

Because the new connection (conn) is completely decoupled from the listener (ln), we can immediately hand conn over to a Goroutine.

go handle(conn) // This runs in the background
go

The main loop stays unblocked, the Listener stays at the front desk, and Go’s runtime manages thousands of these “Room Keys” concurrently.

What is a Socket?
https://theunknown.site/blog/socket
Author TheUnknownThing
Published at December 6, 2025
Comment seems to stuck. Try to refresh?✨
浙ICP备2025146421号-2 浙公网安备33010502012191号