如何摆脱TCP阻塞connect()调用

How to get out from a TCP blocking connect() call?

本文关键字:调用 connect 阻塞 何摆脱 TCP      更新时间:2023-10-16
    int tcp_sock = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);    
    struct sockaddr_in remoteaddr;
    struct sockaddr_in localAddr;
    short local_port = 22222;
    short remote_port = 33333;
    // local addr
    localAddr.sin_family      = AF_INET;
    localAddr.sin_port        = htons(local_port);
    localAddr.sin_addr.s_addr = 0xC0A80AA5; // we don't give a shit
    int addrLen = sizeof(struct sockaddr_in);
    //Now bind TCP to local addr
    int result = bind(tcp_sock,(struct sockaddr*)&localAddr,addrLen);
    if (result < 0)
    {
        perror("nbind failed");
        close(tcp_sock);
        return -1;
    }
    result = connect(tcp_sock, (struct sockaddr*)&remoteaddr, sizeof(struct sockaddr_in));
    printf("nConnect returned %d, error no: %d", result, errno);

在这里,connect()调用在很长一段时间后失败。有什么方法可以让connect函数在我选择的时间后返回?我尝试从另一个线程调用close(),但这不会改变任何东西。

在调用 connect() 之前将套接字置于非阻塞模式,然后您可以使用 select() 指定超时。 select()会告诉您连接是成功还是超时。 如果成功,您可以根据需要将套接字重新置于阻塞模式。 如果失败/超时,请改为关闭套接字。

int tcp_sock = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);    
...
int flags = fcntl(tcp_sock, F_GETFL, 0);
fcntl(tcp_sock, F_SETFL, flags | O_NONBLOCK);
int errCode = 0;
result = connect(tcp_sock, ...);
if (result < 0)
{
    errCode = errno;
    if (errCode == EINPROGRESS)
    {
        fd_set wfd;
        FD_ZERO(&wfd);
        FD_SET(tcp_sock, &wfd);
        struct timeval timeout;
        timeout.tv_sec = ...;
        timeout.tv_usec = ...;
        result = select(tcp_sock+1, NULL, &wfd, NULL, &timeout);
        if (result > 0)
        {
            socklen_t len = sizeof(errCode);
            result = getsockopt(tcp_sock, SOL_SOCKET, SO_ERROR, &errCode, &len);
            if (result < 0)
                errCode = errno;
            else
                result = (errCode == 0) ? 0 : -1;
        }
        else if (result == 0)
        {
            errCode = ETIMEDOUT;
            result = -1;
        }
        else
        {
            errCode = errno;
        }
    }
}
if (result == 0)
{
    // connected
    fcntl(tcp_sock, F_SETFL, flags);
    ...
}
else
{
    // error, use errCode as needed
    ...
}

有什么方法可以让连接函数在我选择的时间后返回?

向进程发送信号。

#define TIME_OUT_SECONDS (15)
void alarm_handler(int sig)
{
   /* Do nothing. */
}
int main(void)
{
  ...
  signal(alarm_handler);
  alarm(TIME_OUT_SECONDS);
  result = connect(tcp_sock, ...);
  ...

如果需要时间,退出连接的唯一方法是使套接字不阻塞。如果是阻塞套接字,则无法退出。

有什么方法可以让连接函数在我选择的时间后返回?

您的选择是将套接字标记为非阻塞。没有其他办法。阻塞意味着"阻塞"执行线程,直到套接字上发生事件。您不能根据需要同时设置阻塞套接字和超时。

使用、selectepoll机制来监视套接字。