c - 如何管理大量socket

标签 c sockets

我开发了一个C软件,它使用不同的循环在IP和端口上打开套接字(例如192.168.1.10端口= 80),并检查是否有人打开; 这是代码:

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



int main(void)
{
    int sockfd = 0,n = 0;
    char recvBuff[1024];
    struct sockaddr_in serv_addr;

    memset(recvBuff, '0' ,sizeof(recvBuff));
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0))< 0)
    {
        printf("\n Error : Could not create socket \n");

    }

    serv_addr.sin_family = AF_INET;
    int i;
    char buf[15];

    for (i = 1; i < 255; i++) {
        sprintf(buf, "192.168.1.%d", i); // puts string into buffer
        for (int port = 0; port<=1024; port++) {
//            Problem
//            int sockfd = 0,n = 0;
//            char recvBuff[1024];
//            struct sockaddr_in serv_addr;
//            
//            memset(recvBuff, '0' ,sizeof(recvBuff));
//            if((sockfd = socket(AF_INET, SOCK_STREAM, 0))< 0)
//            {
//                printf("\n Error : Could not create socket \n");
//                return 1;
//            }
            serv_addr.sin_port = htons(port);
            serv_addr.sin_addr.s_addr = inet_addr(buf);
            if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))<0)
            {
               // printf("The port %d of host %s is not open \n",port,buf);

            }else{
                printf("The port %d of host %s is open \n",port,buf);
            }
        }

    }
    return 0;
}

在第二个版本中,我添加了connection_nonblocking方法,这减少了可能出现的问题。 这是使用OpenMP指令来提高性能的版本;你有什么改进的想法吗?

    #include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <time.h>
#include <omp.h>


int connect_nonblock (int sockfd, const struct sockaddr *saptr, socklen_t salen)
{
    int n, valopt;
    socklen_t len;
    fd_set rset;
    struct timeval tv;
    long int arg;

    arg = fcntl(sockfd, F_GETFL, NULL);
    arg |= O_NONBLOCK;
    fcntl(sockfd, F_SETFL, arg);

    n = connect(sockfd, saptr, salen);

    if (n == 0) {
        // completed immediately
        arg &= (~O_NONBLOCK);
        fcntl(sockfd, F_SETFL, arg);
        close(sockfd);

        return 0;
    }

    if (n < 0) {
        if (errno != EINPROGRESS) {
            // fail somehow...
            arg &= (~O_NONBLOCK);
            fcntl(sockfd, F_SETFL, arg);
            close(sockfd);
            return -1;
        }
        else {
            tv.tv_sec = 0;
            tv.tv_usec = 10000;
            FD_ZERO(&rset);
            FD_SET(sockfd, &rset);
            n = select(sockfd + 1, NULL, &rset, NULL, &tv);
            if (n < 0 && errno != EINTR) {
                arg &= (~O_NONBLOCK);
                fcntl(sockfd, F_SETFL, arg);
                close(sockfd);
                return -1;
            }
            else if (n > 0) {
                len = sizeof(int);
                getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &len);
                if (valopt != 0) {
                    arg &= (~O_NONBLOCK);
                    fcntl(sockfd, F_SETFL, arg);
                    close(sockfd);
                    return -1;
                }
            }
            else {
                arg &= (~O_NONBLOCK);
                fcntl(sockfd, F_SETFL, arg);
                close(sockfd);
                return -1;
            }
        }
    }

    arg &= (~O_NONBLOCK);
    fcntl(sockfd, F_SETFL, arg);
    close(sockfd);

    return 0;
}

int main(void)
{
    int sockfd = 0;
    struct sockaddr_in serv_addr;
    int i, port;
    char buf[15];
    double end, start = omp_get_wtime();
    for (i = 1; i <= 255; i++) {
        sprintf(buf, "192.168.1.%d", i); // puts string into buffer
        fprintf(stdout, "Checking address: %s\n", buf);
        //omp_set_num_threads(1);
        #pragma omp parallel for private(sockfd,serv_addr,port)

        for (port = 0; port <= 1024; port++) {
            if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
            {
                perror("socket");
            }

            memset(&serv_addr, 0, sizeof(serv_addr));
            serv_addr.sin_family = AF_INET;
            serv_addr.sin_port = htons(port);
            serv_addr.sin_addr.s_addr = inet_addr(buf);

            if (connect_nonblock(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
                /* uncoment this but if you want */
                //fprintf(stdout, "The port %d of host %s is not open.\n", port, buf);
                ;
            }
            else {
                fprintf(stdout, "The port %d of host %s is open.\n", port, buf);
            }
        }

    }
    end = omp_get_wtime();
    printf("Elapsed time = %f sec\n", end-start);
    return 0;
}

最佳答案

正如评论中提到的,您没有关闭套接字。您可以使用close因为这是一个文件描述符。但如果扫描大量地址,如果连接超时失败,将非常耗时。 我添加了稍微修改过的代码:

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

 int connect_nonblock (int sockfd, const struct sockaddr *saptr, socklen_t salen)
    {
        int n, valopt;
        socklen_t len;
        fd_set rset;
        struct timeval tv;
        long int arg;

        arg = fcntl(sockfd, F_GETFL, NULL);
        arg |= O_NONBLOCK;
        fcntl(sockfd, F_SETFL, arg);

        n = connect(sockfd, saptr, salen);

        if (n == 0) {
            /* completed immediately */
            arg &= (~O_NONBLOCK);
            fcntl(sockfd, F_SETFL, arg);
            close(sockfd);

            return 0;
        }

        if (n < 0) {
            if (errno != EINPROGRESS) {
                /* fail somehow... */
                arg &= (~O_NONBLOCK);
                fcntl(sockfd, F_SETFL, arg);
                close(sockfd);
                return -1;
            }
            else {
                tv.tv_sec = 0;
                tv.tv_usec = 10000;
                FD_ZERO(&rset);
                FD_SET(sockfd, &rset);
                n = select(sockfd + 1, NULL, &rset, NULL, &tv);
                if (n < 0 && errno != EINTR) {
                    arg &= (~O_NONBLOCK);
                    fcntl(sockfd, F_SETFL, arg);
                    close(sockfd);
                    return -1;
                }
                else if (n > 0) {
                    len = sizeof(int);
                    getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &len);
                    if (valopt != 0) {
                        arg &= (~O_NONBLOCK);
                        fcntl(sockfd, F_SETFL, arg);
                        close(sockfd);
                        return -1;
                    }
                }
                else {
                    arg &= (~O_NONBLOCK);
                    fcntl(sockfd, F_SETFL, arg);
                    close(sockfd);
                    return -1;
                }
            }
        }

        arg &= (~O_NONBLOCK);
        fcntl(sockfd, F_SETFL, arg);
        close(sockfd);

        return 0;
    }

    int main(void)
    {
        int sockfd = 0, n = 0;
        char recv_buff[1024];
        struct sockaddr_in serv_addr;
        int i, port;
        char buf[15];

        memset(recv_buff, '0', sizeof(recv_buff));

        for (i = 1; i < 255; i++) {
            sprintf(buf, "192.168.88.%d", i); // puts string into buffer
            for (port = 0; port <= 1024; port++) {
                if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
                {
                    perror("socket");
                    return EXIT_FAILURE;
                }

                memset(&serv_addr, 0, sizeof(serv_addr));
                serv_addr.sin_family = AF_INET;
                serv_addr.sin_port = htons(port);
                serv_addr.sin_addr.s_addr = inet_addr(buf);

                if (connect_nonblock(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
                {
                    printf("The port %d of host %s is not open \n", port, buf);
                } else {
                    printf("The port %d of host %s is open \n", port, buf);
                }

                // you missed this
                close(sockfd);
             }
         }
         return 0;
     }

我使用 select 添加一种非阻塞方法,超时和线程很少。应该重新制作,因为很多错误检查没有以正确的方式完成。但希望你能明白这个想法。

关于c - 如何管理大量socket,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28570275/

相关文章:

c - 拆分以逗号分隔的整数字符串

将字符串数组中的值连接到 c 中的另一个静态字符串

linux - 当数据部分以 2 开头时无法读取接收到的数据包

c - C中的Read()整数

c - C 中的这种多管道代码有意义吗?

使用 "<"或 ">"运算符比较字符串 (C)

python - 当你抛出异常时,Python 对象会发生什么

c - 检查通过程序的 C 管道——边界情况

mysql - MAMP - phpMyAdmin #2002 - 无法通过套接字 '/Applications/MAMP/tmp/mysql/mysql.sock' 连接到本地 MySQL 服务器

windows - Windows 8 应用商店应用程序可以通过 UDP/TCP 套接字与 Windows 7 桌面应用程序通信吗?