从不同套接字连接和侦听同一端口无法处理传入的SYN(MAC OSX)

时间:2015-09-22 06:14:31

标签: c++ macos sockets tcp

我有两个同龄人。对等A(MAC OSX)在同一端口上绑定了两个套接字。一个在主动模式下操作,一个在被动模式下操作。对等B(任何操作系统)只有一个套接字作用于活动模式。对等A开始在单独的线程中侦听。之后,从另一个线程调用Connect。但是对等B没有收听,所以A的连接呼叫失败了。然后Peer B呼叫Connect,但此连接也失败。

在wireshark中,我看到SYN离开B并进入A的电脑。但是A的Accept API调用不会返回有效的FD,这意味着A无法处理SYN。所以没有SYN-ACK也离开了A的PC。

如果对等体A是除MAC以外的任何操作系统(例如windows,ubuntu,centos),则不会再现此问题。

修改

在创建套接字时,我们设置了一些套接字选项。它们是O_NONBLOCK,TCP_NODELAY,SO_REUSEADDR,SO_LINGER和OSX,iOS SO_NOSIGPIPE。

CODE:

这是A的听力部分。

int iAcceptResult = -1;

if (::listen(currentTcpSocket,1)< 0)
{
    Log("Listen error: " + itoa(LastNetworkError());
}   

unsigned int i = 0;
while ((iAcceptResult < 0 )
{
    sleep(80);
    iAcceptResult = Accept(currentTcpSocket);
    if (0 == iAcceptResult)
    {
        //success
        break;
    }       
}

这是A和B的连接部分。

int iConnect = Connect(currentTcpSocket, uAddr, uPort);
if (iConnect < 0)
{
    return false;
}
int connectTimeout = 750; //milliseconds
int nWaitResult = UseSelect(currentTcpSocket,connectTimeout);
if (nWaitResult != 0)       
{
    // timeout or error
}

连接,接受和使用选择功能

int Connect(SOCKET sock, const IpAddress& uAddr, u_int16_t uPort)
{
    struct sockaddr_in sin;
    memset((char *)&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = uPort;
    sin.sin_addr = uAddr.addr4;

    return ::connect(sock, (struct sockaddr *)&sin, sizeof(sin));
}

int Accept(SOCKET m_sock)
{
    sock_accept = ::accept(m_sock, NULL, NULL);
    if (INVALID_SOCKET == sock_accept)
        return -1;   
    return 0;
}

int UseSelect(SOCKET fd, int iTimeoutMs)
{
    fd_set readEvents;
    fd_set writeEvents;
    fd_set exceptEvents;

    FD_ZERO(&writeEvents);
    FD_ZERO(&readEvents);
    FD_ZERO(&exceptEvents);
    FD_SET(fd, &exceptEvents);

    if(true == read)
    {
        FD_SET(fd, &readEvents);
    }
    else
    {
        FD_SET(fd, &writeEvents);
    }

    timeval timeout;
    timeout.tv_sec = iTimeoutMs / 1000;
    timeout.tv_usec = (iTimeoutMs % 1000) * 1000;   


    return ::select(fd + 1, &readEvents, NULL, &exceptEvents, &timeout);
}

0 个答案:

没有答案