2

我面临一个奇怪的问题,也许它很简单,但我缺乏太多的套接字知识也无济于事。

我创建了一个套接字程序,它在单独的程序中运行时完美运行,即在 main 中作为独立的 exe 单独运行。正如您在代码中看到的,在这个单独的程序中运行时,返回的套接字 fd 始终为 3。

当我复制同一段代码并将其集成到另一个打开了它自己的 fd 的服务器程序时,无论如何选择总是返回 0。在这种情况下,我的程序创建的 fd 始终为 6。

请参阅下面的程序。这段代码没有问题,只是在另一个服务器中运行时,select总是返回0。

当程序中已经存在一个 UDP 套接字 fd 时,我可以创建一个新的 UDP 套接字 fd。当我的套接字 fd 与程序中已经打开的套接字不同时,为什么会发生这种情况。

为什么会发生这种情况,任何人都可以指导我该怎么做,或者任何指示都会有所帮助。

#define MY_TIMEOUT_S    5   
    int mySock;
    if ((mySock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("Cannot create UDP socket");
        return -1;
    }

    struct sockaddr_in myAddr;
    myAddr.sin_family       = AF_INET;
    myAddr.sin_port         = 0;
    myAddr.sin_addr.s_addr  = INADDR_ANY;
    memset(&(myAddr.sin_zero), '\0', 8);
    if (bind(mySock, (struct sockaddr*)&myAddr, 
            sizeof(struct sockaddr)) == -1) {
        perror("Cannot bind UDP socket to desired port");
        close(mySock);
        return -1;
    }

    // here send to remote target host on udp socket and port 

    char buf[MAX_UDP_PACKET_SIZE];
    struct sockaddr_in theirAddr;
    int addrLen = sizeof(struct sockaddr);

    fd_set readSet, curReadSet;
    FD_ZERO(&readSet);
    FD_SET(mySock, &readSet);
    int maxFD = mySock;
    while (true) {
        struct timeval timeOutTV = {MY_TIMEOUT_S, 0};

        memcpy(&curReadSet, &readSet, sizeof(fd_set));

        int selectRet = select(maxFD+1, &curReadSet, NULL, NULL, &timeOutTV);
        cout<<"select value =" <<selectRet<<endl;

        if (selectRet == -1) {
            if (errno == EINTR) {
                continue; // Interrupted by signal, retry
            }
            close(mySock);
            return -1;

        } else if (selectRet == 0) {
            close(mySock);
            return -1;
        }
        if (FD_ISSET(mySock, &curReadSet)) {
            int numBytes = recvfrom(mySock, buf, MAX_UDP_PACKET_SIZE, 0,
                    (struct sockaddr*)&theirAddr, (socklen_t*)&addrLen);
            if (numBytes == -1) {
                close(mySock);
            }   

        }
    }

从 lsof 输出添加一些细节

1)这是我必须发送数据的目标 sudo lsof -a -p 16061

目标 16061 根 3r FIFO 0,8 0t0 153467 管道
目标 16061 根 4u IPv4 153470 0t0 UDP *:3290
目标 16061 根 5u sock 0,6 0t0 153471 无法识别协议
目标 16061 根 6u IPv4 153472 0t0 TCP *:3290 ( )
目标 16061 根 7u 原始 0t0 153473 00000000:0001->00000000:0000 st=07

2)这是我在单独的exe中运行时的上述代码,其中只有这是在main中运行的代码,因为FD = 3工作正常

须藤 lsof -a -p 16112

myProg 16112 根 0u CHR 136,4 0t0 7 /dev/pts/4
myProg 16112 根 1u CHR 136,4 0t0 7 /dev/pts/4
myProg 16112 根 2u CHR 136,4 0t0 7 /dev/pts/4
myProg 16112根 3u IPv4 153564 0t0 UDP *:60503

3)这是我在其中集成了上面相同的代码的 Web 服务器,它独立工作,但现在不是

这是我的网络服务器运行的输出

webServ 18431 root 3u unix 0xc09f9b00 0t0 157975 socket
webServ 18431 root 4u IPv4 157976 0t0 UDP *:8080
webServ 18431 root 5u IPv4 157977 0t0 TCP *:8080 (LISTEN)

现在我发送请求并在服务器端执行我的新集成代码,我放置了一个无限循环并且没有关闭套接字只是为了显示 lsof 输出

4)我整合后的输出

webServ 18449 root 3u unix 0xc09f9b00 0t0 157975 socket
webServ 18449 root 4u IPv4 157976 0t0 UDP *:8080
webServ 18449 root 5u IPv4 157977 0t0 TCP *:8080 (LISTEN)
webServ 18449 root 6u IPv4 *:158038

唯一的区别是当集成到服务器时,socket FD 是不同的,这是唯一的区别。

希望这有助于回答我的问题。

我不确定为什么会这样。请帮忙

4

2 回答 2

0

也许select会有maxFd + 1帮助?

编辑:我再次查看了您的代码(尽管您现在可能已经自己解决了)。我有三个建议。

首先,当您bind使用套接字时,myAddr.sin_port0. 因此选择了一个临时端口号。此端口号在您的 myProg 和 webServ 程序之间有所不同:

myProg  16112 root 3u IPv4 153564 0t0 UDP *:60503  
webServ 18449 root 6u IPv4 158389 0t0 UDP *:48057  

因此,我对您一直使用哪个端口号将 UDP 发送到 myProg 感到困惑。

其次,您的超时时间为select5 秒,之后您关闭套接字并离开。你怎么知道你会在打开端口的 5 秒内收到一个数据包?为了确保这一点,发送程序将需要(例如)连续尝试每 4 秒或更短时间发送一个数据包,这似乎不合理。

第三,这可能是一个小问题,但可能是你的问题,在:

        if (numBytes == -1) {
            close(mySock);
        }

您省略了在其他地方使用的,因此如果返回诸如 EINTR 之类的错误,return -1;您将陷入无限循环。recvfrom此外,在这里和其他地方打电话perror会很好。

最后是评论:

  // here send to remote target host on udp socket and port

不正确,您正在接收.

于 2012-11-22T07:16:15.217 回答
0

做到这一点:

int maxFD = mySock + 1;

select(2)的手册页说:

int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);

nfds是三组中编号最高的文件描述符,加上 1

于 2012-11-22T07:16:28.673 回答