1

我正在尝试通过执行非阻塞连接来检查网络上的主机,然后执行选择以查看套接字是否可写或异常不足。我尝试通过端口 80,139 建立套接字连接。主机如果套接字在连接之后是可写的,或者当主机发送 RST 数据包等时它进入异常时,将可以发现。

我已经使用 Windows 套接字编写了一个代码并且逻辑工作正常,但是使用 linux 套接字程序没有给出期望的结果。即使该 ip 上没有主机,选择函数也会为任何给定的 ip 地址返回 1。选择会winsock 的情况下返回 0 超时。我写了下面的代码,让我知道问题到底出在哪里。

#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

int port[]={80,139};

void Free(int Sock_Arr[])
{
    for(int i=0;i<2;i++)
    {
        close(Sock_Arr[i]);
    }
    return ;
}

int  main()
{
    int Socket[2],result=0; //Socket array
    struct sockaddr_in service;


    fd_set writefds;
    fd_set exceptfds;


    struct timeval timer;
    timer.tv_sec=5;

    timer.tv_usec=0;

    int flag=0;

    FD_ZERO(&writefds);
    FD_ZERO(&exceptfds);


    char Ip_Addr[20];
    for(int i=0;i<2;i++)
    {
        if((Socket[i]=socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0)
        {
             Free(Socket);
        }
        fcntl(Socket[i],F_SETFL,O_NONBLOCK);



    }

    bzero(&service, sizeof(sockaddr_in));

    printf("Enter the ip-address : ");
    scanf("%s",Ip_Addr);



    service.sin_family=AF_INET;
    service.sin_addr.s_addr=inet_addr(Ip_Addr);



    for(int i=0;i<2;i++)
    {


        FD_SET(Socket[i],&writefds);
        FD_SET(Socket[i],&exceptfds);
        service.sin_port=htons((unsigned short int )port[i]);
        connect(Socket[i],(struct sockaddr *)&service,sizeof(sockaddr_in));



        result= select(Socket[i]+1,NULL,&writefds,&exceptfds,&timer);

        if(result<0||result==0)
        {
                flag=0;
                printf("\n The machine could not be found on the port %d ",port[i]);
                printf("result : %d",result);
                perror("select");

        }
        else
        {

                printf("\n The machine could  be found on the port %d ",port[i]);
                flag=1;
                printf("result : %d",result);

                if(FD_ISSET(Socket[i],&writefds))
                {
                    printf("The socket triggered on write on port %d",port[i]);
                }

                else if(FD_ISSET(Socket[i],&exceptfds))
                {
                    printf("The socket triggered on except on port %d",port[i]);
                }
                else
                {
                    printf("No socket triggered on %d",port[i]);
                }

        }

        FD_ZERO(&writefds);
        FD_ZERO(&exceptfds);



    }

    Free(Socket);

    if(flag==1)
    {
        return 1;
    }
    else
    {
        return 0;
    }



}
4

1 回答 1

1

这里

result= select(Socket[i],NULL,&writefds,&exceptfds,&timer);

第一个参数select应该是你想要的最大文件描述符select()+ 1。因为你只是 l 你没有加 1,这可能会导致问题。尝试

result= select(Socket[i]+1,NULL,&writefds,&exceptfds,&timer);

实际上最好不要在套接字上循环并将所有套接字文件描述符添加到 fd_sets,计算出最大的文件描述符,执行所有非阻塞connect调用,然后只使用一次 select 调用来检查套接字活动在其中任何一个上(使用最大的文件描述符 +1 作为选择的第一个参数)。然后如果select()返回正数,您可以使用它FD_ISSET来确定select()触发的套接字;通过这种方式,您可以select()一次在多个套接字上查找活动。当我在多个套接字上监听活动时,我就是这样做的。

至少,您可能应该在每次迭代执行connect()调用的第二个循环时清除 fd_set,因为您没有删除您在先前迭代中添加的套接字 fd,因此您可能正在寻找其他套接字上的活动除了当前添加的一个。

此外,按照您的方式执行此操作,您不会重置您发送给select()呼叫的超时值。从select手册页中清楚地说明select 可能会更改超时值。因此,如果是这种情况,您的超时可能已被后续迭代调用减少,以select尝试在每次迭代时也将超时重置为 5 秒。如果超时减少到为零,则 select() 调用将立即返回(轮询)。

于 2013-10-11T09:06:12.617 回答