非阻塞情况下connect产生EINPROGRESS错误

本文探讨了在网络编程中使用非阻塞socket时,connect函数返回-1且错误码为EINPROGRESS的情况。文章详细介绍了如何通过select和poll机制来判断连接是否成功建立,并提供了具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天在开发游戏客户端测试程序时,由于出现很多客户端,经过connect成功后,代码卡在recv系统调用中,后来发现可能是由于socket默认是阻塞模式,所以会令很多客户端

链接处于链接却不能传输数据状态。


后来修改socket为非阻塞模式,但在connect的时候,发现返回值为-1,刚开始以为是connect出现错误,但在服务器上看到了链接是ESTABLISED状态。证明链接是成功的

但为什么会出现返回值是-1呢? 经过查询资料,以及看stevens的APUE,也发现有这么一说。


当connect在非阻塞模式下,会出现返回-1值,错误码是EINPROGRESS,但如何判断connect是联通的呢?stevens书中说明要在connect后,继续判断该socket是否可写?


若可写,则证明链接成功。如何判断可写,有2种方案,一种是select判断是否可写,二用poll模型。


select:

int CheckConnect(int iSocket)
{
fd_set rset;

FD_ZERO(&rset);
FD_SET(iSocket, &rset);

timeval tm;
tm. tv_sec = 0;
tm.tv_usec = 0;

if ( select(iSocket + 1, NULL, &rset, NULL, &tval) <= 0)
{
    close(iSocket);
    return -1;
}

if (FD_ISSET(iSocket, &rset))
{
    int err = -1;
    socklen_t len = sizeof(int);
if ( getsockopt(iSocket,  SOL_SOCKET, SO_ERROR ,&err, &len) < 0 )
{
    close(iSocket);
    printf("errno:%d %s\n", errno, strerror(errno));
    return -2;
}

if (err)
{
    errno = err;
    close(iSocket);
   
  return -3;
}
}

return 0;
}


poll:

int CheckConnect(int iSocket) {
	struct pollfd fd;
	int ret = 0;
	socklen_t len = 0;

	fd.fd = iSocket;
	fd.events = POLLOUT;

	while ( poll (&fd, 1, -1) == -1 ) {
		if( errno != EINTR ){
			perror("poll");
			return -1;
		}
	}

	len = sizeof(ret);
	if ( getsockopt (iSocket, SOL_SOCKET, SO_ERROR, &ret, &len) == -1 ) {
    	        perror("getsockopt");
		return -1;
	}

	if(ret != 0) {
		fprintf (stderr, "socket %d connect failed: %s\n",
                 iSocket, strerror (ret));
		return -1;
	}

	return 0;
}
<think>好的,用户想了解TCP连接中EINPROGRESS错误的原因及解决方法。首先,我需要回忆一下这个错误通常发生在什么情况下EINPROGRESS错误通常与非阻塞套接字有关,当连接不能立即完成时,系统会返回这个错误,表示操作正在进行中。用户可能需要知道为什么会出现这个错误,以及如何处理它。 接下来,我得确认这个错误的具体原因。当使用非阻塞模式的套接字调用connect()时,连接过程不会阻塞,而是立即返回。如果连接不能马上建立,比如需要等待三次握手完成,这时候errno会被设置为EINPROGRESS。用户可能需要了解如何检查连接是否成功,以及如何处理后续的步骤,比如使用select或poll来监视套接字的状态。 然后,解决方法方面,通常需要处理非阻塞连接的正确流程。包括设置套接字为非阻塞模式,调用connect(),处理EINPROGRESS错误,然后使用select、poll或epoll来等待连接完成,最后检查套接字是否可写,并通过getsockopt()获取错误状态。这些步骤都需要详细说明,确保用户能够正确实现。 另外,用户可能想知道具体的代码示例,特别是使用C语言和Python的情况。比如在C中,设置非阻塞套接字,处理错误,使用select等。在Python中,可能需要使用socket模块,设置setblocking(False),然后捕获BlockingIOError异常,再使用selectors模块来等待连接完成。这部分需要检查Python的相关文档,确保示例的正确性,比如引用提到的termios和fcntl可能和终端设置有关,但这里主要关注socket操作。 还需要注意错误处理,比如在检查连接是否成功时,如果getsockopt()返回的错误不是0,说明连接失败,这时候需要处理具体的错误码,比如ECONNREFUSED。同时,超时时间的设置也很重要,避免程序无限等待。 用户可能遇到的问题还包括如何处理异步连接中的其他错误,或者在多线程环境下的注意事项。引用中的线程部分提到Python中如何编程使用线程,但可能和当前问题关联不大,不过需要确认Python中处理非阻塞socket的正确方式,比如是否正确处理异常和使用选择器模块。 最后,要确保回答结构清晰,分点说明原因和解决方法,并提供代码示例。同时,生成的相关问题需要与主题相关,比如非阻塞socket的其他错误、设置非阻塞模式的正确方法、检查连接状态的替代方法,以及处理异步连接时的超时设置。</think>### TCP连接中EINPROGRESS错误的原因及解决方法 #### 1. 错误原因 在TCP连接中,`EINPROGRESS`错误发生在以下场景: - **非阻塞套接字**:当使用非阻塞模式(通过`fcntl/O_NONBLOCK`或`socket.setblocking(False)`设置)的套接字调用`connect()`时,若连接无法立即完成(如需要等待三次握手),系统会返回此错误,表示操作正在后台进行[^1][^2]。 - **异步操作特性**:该错误并非致命错误,而是提示开发者需要通过I/O多路复用(如`select`、`poll`或`epoll`)监听套接字可写事件,以判断连接是否最终成功。 #### 2. 解决方法 ##### 步骤1:设置非阻塞模式 ```c // C语言示例 int flags = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); ``` ```python # Python示例 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setblocking(False) ``` ##### 步骤2:调用connect并处理错误 ```c // C语言示例 int ret = connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)); if (ret < 0 && errno != EINPROGRESS) { // 处理其他错误 } ``` ```python # Python示例 try: sock.connect((host, port)) except BlockingIOError: # 符合预期的EINPROGRESS状态 pass ``` ##### 步骤3:通过I/O多路复用监听可写事件 ```c // C语言使用select fd_set writefds; FD_ZERO(&writefds); FD_SET(sockfd, &writefds); struct timeval timeout = {5, 0}; // 5秒超时 select(sockfd + 1, NULL, &writefds, NULL, &timeout); ``` ```python # Python使用selectors import selectors sel = selectors.DefaultSelector() sel.register(sock, selectors.EVENT_WRITE) events = sel.select(timeout=5) ``` ##### 步骤4:检查连接结果 ```c // C语言通过getsockopt获取错误状态 int error = 0; socklen_t len = sizeof(error); getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len); if (error != 0) { // 处理连接失败(如ECONNREFUSED) } ``` ```python # Python检查异常 if sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) != 0: raise ConnectionError("Connection failed") ``` #### 3. 关键注意事项 - **超时设置**:必须为异步连接设置合理的超时时间,避免无限等待 - **错误传播**:最终需通过`getsockopt`获取底层真实错误码 - **可写事件触发**:套接字可写**不一定**表示连接成功,需结合错误状态判断
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值