【socket编程中的常规操作,阻塞/非阻塞模式的差别】
我们来详细讲解一下 Socket 编程的常规操作以及阻塞与非阻塞模式的核心差别。这对于理解网络编程至关重要。
第一部分:Socket 编程的常规操作
Socket 编程就像是两部电话之间的通信过程。下面我们以最常见的 TCP 协议为例,讲解其常规操作步骤。
服务端 (Server) - “接电话的人”
服务端的流程可以概括为:创建 -> 绑定 -> 监听 -> 接受 -> 通信 -> 关闭。
-
创建 Socket (socket)
-
使用
socket()
系统调用创建一个通信端点(Socket)。这相当于买一部电话机。 -
需要指定地址族(如
AF_INET
用于 IPv4)、套接字类型(如SOCK_STREAM
用于 TCP)和协议。 -
int server_socket = socket(AF_INET, SOCK_STREAM, 0);
-
-
绑定地址 (bind)
-
使用
bind()
将 Socket 与一个本地 IP 地址和端口号绑定。这相当于给电话机申请一个电话号码。 -
服务端必须这么做,以便客户端能够找到它。
-
bind(server_socket, (struct sockaddr*) &server_addr, sizeof(server_addr));
-
-
监听连接 (listen)
-
使用
listen()
告诉操作系统,这个 Socket 愿意接受传入的连接请求,并设置连接请求队列的最大长度。这相当于把电话机的铃声打开,并准备好接听。 -
listen(server_socket, 5); // 队列长度为5
-
-
接受连接 (accept)
-
使用
accept()
阻塞地等待客户端的连接请求。当有客户端连接时,它返回一个新的 Socket 用于与这个特定的客户端通信。 -
这相当于拿起响铃的电话听筒。原来的 Socket 仍然用于继续监听新的连接。
-
int client_socket = accept(server_socket, (struct sockaddr*) &client_addr, &client_addr_len);
-
-
数据交换 (read/write 或 recv/send)
-
使用
read()
/recv()
从客户端 Socket 接收数据。 -
使用
write()
/send()
向客户端 Socket 发送数据。 -
这相当于在电话中和对方交谈。
-
-
关闭连接 (close)
-
通信完毕后,使用
close()
关闭 Socket,释放资源。这相当于挂断电话。 -
close(client_socket);
关闭与客户端的连接。 -
close(server_socket);
关闭监听套接字(通常服务端不会关闭这个)。
-
客户端 (Client) - “打电话的人”
客户端的流程更简单:创建 -> 连接 -> 通信 -> 关闭。
-
创建 Socket (socket)
-
和服务端一样,先“买一部电话机”。
-
int client_socket = socket(AF_INET, SOCK_STREAM, 0);
-
-
建立连接 (connect)
-
使用
connect()
向服务端的地址(IP 和端口)发起连接请求。这相当于拨打对方的电话号码。 -
connect(client_socket, (struct sockaddr*) &server_addr, sizeof(server_addr));
-
-
数据交换 (read/write)
-
连接建立后,就可以像服务端一样使用
read()
和write()
进行通信了。
-
-
关闭连接 (close)
-
通信完毕,关闭 Socket。
-
close(client_socket);
-