好久没有接触这块了,之前一直直接使用各种网络库,libevent
之类的,突然发现非阻塞的connect不会了。。。
好了,不会就查个资料,然后记一下笔记,以防后续又忘了。
首先,前面的流程很简单,将socket设置为非阻塞然后进行connect,这里就不多说了。
connect后,需要判断返回值,这里有几种情况:
主要的处理流程在于EINPROGRESS
上,主要是要注册一下EPOLLOUT(可写)事件,然后进行监听。
假设可写了,那么连接过程也就有结果了,这里先放上man中的文档:
EINPROGRESS The socket is non-blocking and the connection cannot be completed immediately. It is possible to select(2) or poll(2) for completion by selecting the socket for writing. After select(2) indicates writability, use getsock-opt(2) to read the SO_ERROR option at level SOL_SOCKET to determine whether connect() completed successfully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining the reason for the failure).
当fd可写了之后,去读一下fd的SO_ERROR来判断连接是否成功,libevent
在这里的处理是:
/* Check whether a socket on which we called connect() is done
connecting. Return 1 for connected, 0 for not yet, -1 for error. In the
error case, set the current socket errno to the error that happened during
the connect operation. */
int
evutil_socket_finished_connecting(evutil_socket_t fd)
{
int e;
ev_socklen_t elen = sizeof(e);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&e, &elen) < 0)
return -1;
if (e) {
if (EVUTIL_ERR_CONNECT_RETRIABLE(e))
return 0;
EVUTIL_SET_SOCKET_ERROR(e);
return -1;
}
return 1;
}
可以看到,在处理可写事件的时候,会先读取错误信息,假设有错,则连接失败。同时判断SO_ERROR获取的值,非零的话,假设为EINPROGRESS,则继续后续的连接状态判断,其余直接为连接失败。