【问题标题】:Host Discovery on LAN using non blocking connect使用非阻塞连接在 LAN 上发现主机
【发布时间】:2013-10-11 18:05:52
【问题描述】:

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

我使用 Windows 套接字编写了一个代码,并且逻辑运行良好,但是使用 linux 套接字,程序没有给出预期的结果。即使该 ip 上没有主机,select 函数也会为任何给定的 ip 地址返回 1。在winsock的情况下select会超时返回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;
    }



}

【问题讨论】:

  • 有点离题但仍然:1)不要使用bzero,使用memset。 2)您不将数组传递给函数,而是将指针传递给数组。 3)不要使用像Free(或Close或任何容易被误认为标准调用的函数名)。

标签: c sockets


【解决方案1】:

这里

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

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

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

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

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

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

【讨论】:

  • 我也这样做了,但没有用。它正在为所有内容返回一个。
  • 我已经编辑并粘贴了上面的代码,现在select总是在第一个端口上返回true,但在第二个端口上没有。我已经按照你的建议完成了步骤。
  • 按照您说的做了,先生,效果很好。太棒了。
猜你喜欢
  • 2011-09-12
  • 2014-06-07
  • 1970-01-01
  • 1970-01-01
  • 2017-04-18
  • 1970-01-01
  • 1970-01-01
  • 2016-07-05
  • 2023-04-09
相关资源
最近更新 更多