TCP通信中客户端调用connect函数时非阻塞式处理
📅 2026/7/29 20:20:57
👁️ 阅读次数
📝 编程学习
一. 简介
本文简单学习一下,TCP网络通信中,客户端 connect函数时非阻塞实现。
二. TCP通信中客户端调用connect函数时非阻塞式处理
1. connect函数
connect函数是 TCP 客户端用于与服务器建立连接的核心系统调用,其作用是发起 TCP 三次握手,建立与目标服务器的可靠连接。
connect 函数是客户端 client 在连接服务器时进行连接时用的。
2. TCP通信中客户端调用connect函数时非阻塞式处理
非阻塞模式下,connect会立即返回-1并设置errno=EINPROGRESS(Linux)或WSAEWOULDBLOCK(Windows),表示连接正在进行中,需通过select/epoll等待结果。
下面举例说明,非阻塞模式下 connect函数的处理方式:
int nonblock_connect(const char *server_ip, int port) { int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { perror("socket failed"); return -1; } // 设置套接字为非阻塞模式 int flags = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); struct sockaddr_in server_addr = { .sin_family = AF_INET, .sin_port = htons(port) }; inet_pton(AF_INET, server_ip, &server_addr.sin_addr); // 非阻塞 connect:立即返回,可能失败但需后续检查 int conn_ret = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)); if (conn_ret == 0) { // 极少数情况:连接立即建立(本地连接) fcntl(sockfd, F_SETFL, flags); // 恢复阻塞模式(可选) return sockfd; } if (errno != EINPROGRESS && errno != EWOULDBLOCK) { // 非阻塞模式下的其他错误(如地址无效) perror("nonblock connect failed immediately"); close(sockfd); return -1; } // 用 select 等待连接完成(超时 5 秒) fd_set writefds; FD_ZERO(&writefds); FD_SET(sockfd, &writefds); struct timeval timeout = {5, 0}; // 5秒超时 int select_ret = select(sockfd + 1, NULL, &writefds, NULL, &timeout); if (select_ret <= 0) { // select 超时或失败 printf("connect timeout or select failed\n"); close(sockfd); return -1; } // 检查连接是否成功(通过 getsockopt 获取错误码) int error = 0; socklen_t error_len = sizeof(error); getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &error_len); if (error != 0) { // 连接失败(错误码为实际失败原因,如 ECONNREFUSED) printf("connect failed (SO_ERROR=%d): %s\n", error, strerror(error)); close(sockfd); return -1; } // 连接成功,恢复阻塞模式(可选,根据需求) fcntl(sockfd, F_SETFL, flags); return sockfd; }可以看出,客户端 client 进行 非阻塞式 connect 连接时,主要使用函数如下:
int fcntl(int fd, int cmd, ... /\* arg \*/ ); int select(int nfds, fd\_set \*readfds, fd\_set \*writefds, fd\_set \*exceptfds, struct timeval \*timeout);
编程学习
技术分享
实战经验