C 中的数组初始化分段错误(核心转储)

segmentation fault (core dumped) in C over array initialization

所以我有一个用 C 编写的服务器代码。我第一次执行它时(在 Linux),它给出了一个 segmentation fault core dumped 错误。但当我再次尝试时,它总是完美无缺。所以我努力调试它,发现我的问题出在客户端数组的初始化中。我有一个数组“int clientSockets[1024];”在我的代码开头声明。当我将它移动到代码中的不同位置(到我实际开始使用它的位置)时,分段错误已经消失,但我收到了总线错误。我将数组的声明移回原来的位置,并改用 malloc() 。这一次,它真的起作用了,我的程序不再崩溃了。但我遇到了另一种错误:我的服务器只接受 7 个客户端,然后永远滞后。它曾经最多接受 1020 个客户端(存储在 clientSockets 数组中)。

我该如何解决这个问题?

我的代码链接如下:

    #include <netinet/in.h>
    #include <netinet/ip.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <unistd.h>
    #include <sys/select.h>
    #include <errno.h>


    #define ECHO_PORT 9999
    #define BUF_SIZE 4096
    #ifndef FD_SETSIZE
    #define FD_SETSIZE 1024
    #endif


    int close_socket(int sock)
    {
        if (close(sock))
        {
            printf("Failed closing socket.\n");
        }
        return 0;
    }

    int main(int argc, char* argv[])
    {
        int sock, client_sock; 
        int *clientSockets = malloc(FD_SETSIZE * sizeof(int));  // the problem lies here
        int monitor; 
        int i; 
        fd_set readfds;
        ssize_t readret;
        socklen_t cli_size;
        struct sockaddr_in addr, cli_addr;
        char buf[BUF_SIZE];

        printf("----- Echo Server -----\n");

if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1)
{
    printf("Failed creating socket.\n");
    return EXIT_FAILURE;
}

addr.sin_family = AF_INET;
addr.sin_port = htons(ECHO_PORT);
addr.sin_addr.s_addr = INADDR_ANY;

if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)))
{
    close_socket(sock);
    printf("Failed binding socket.\n");
    return EXIT_FAILURE;
}

if (listen(sock, 5))
{
    close_socket(sock);
    printf("Error listening on socket.\n");
    return EXIT_FAILURE;
}


for (i = 0 ; i < FD_SETSIZE ; i++) 
{
    clientSockets[i] = 0;
} 


while (1)
{

   FD_ZERO(&readfds); 
   FD_SET(sock, &readfds); 
   int nfds = sock; 

   for (i = 0 ; i < sizeof(clientSockets) ; i++) 
    {   
        if(clientSockets[i] > 0) 
            FD_SET(clientSockets[i] , &readfds); 
        if(clientSockets[i] > nfds) 
            nfds = clientSockets[i];
    }

    nfds++; 

    monitor = select(nfds, &readfds , NULL , NULL , NULL); 
    
    if (monitor < 0) // select() detects error 
    {
        printf("\nERROR:");
        switch(errno)
        {
            case EBADF:
                printf("Invalid file descriptor detected during select().");
            case EINTR:
                printf("A signal was caught during select().");
            case EINVAL:
                printf("Value of nfds is NEGATIVE.");
            case ENOMEM:
                printf("Unable to allocate memory for internal tables");
            default:
                break;
        }
    }


    if (FD_ISSET(sock, &readfds))
    {
        cli_size = sizeof(cli_addr);
        if ((client_sock = accept(sock, (struct sockaddr *) &cli_addr, &cli_size)) == -1)
            {
                close(sock);
                printf("Error accepting connection.\n");
                return EXIT_FAILURE;
            } 


        for (i = 0 ; i < FD_SETSIZE ; i++)
        {
            if (clientSockets[i] == 0) 
            {
                clientSockets[i] = client_sock;
                break;
            }

            if (i == (FD_SETSIZE - 1) && clientSockets[i] != 0)
            {
                printf("Maximum # of clients reached.");
            }
        }
    }

    for (i = 0 ; i < FD_SETSIZE ; i++)
    {
        if (clientSockets[i] != 0) 
        {
            if (FD_ISSET(clientSockets[i], &readfds))
            {
                readret = 0;

                if((readret = recv(clientSockets[i], buf, BUF_SIZE, 0)) >= 1)
                {
                    buf[readret] = '[=10=]';
                    printf("client %d (fd:.  %d) sent %s\n",i,clientSockets[i],buf);
                    if (send(clientSockets[i], buf, strlen(buf), 0) ==  -1)
                        {
                            printf("Error sending back echo to client.");
                        } 
                    memset(buf, 0, BUF_SIZE); 
                }
                if (readret == 0) // client has shut down 
                {
                
                    if (close_socket(clientSockets[i]))
                        {
                          close_socket(sock);
                          printf("Error closing client socket.\n");
                          return EXIT_FAILURE;
                        } 
                    clientSockets[i] = 0;
                }
                if (readret == -1) 
                 {
                     close_socket(clientSockets[i]);
                     close_socket(sock);
                     printf("Error reading from client socket.\n");
                     return EXIT_FAILURE;
                 }
            }
        }
    }
}

close_socket(sock);

return EXIT_SUCCESS;
    }

clientSocket 声明为 int *。它是一个指针,指针的大小是8不管它指向什么。循环

for (i = 0 ; i < sizeof(clientSockets) ; i++)

进行 8 次迭代,并向 readfds 添加最多 7 个客户端(服务器套接字始终占用一个插槽)。

我不知道您使用 int clientSockets[1024]; 的原始代码是什么样的。然而,我的 crystal 球告诉我你有完全相同的循环,

for (i = 0 ; i < sizeof(clientSockets) ; i++)

其中sizeof(clientSocket)是1024个整数占用的大小,即1024 * sizeof(int)。远远超过阵列实际容纳的数量。将其更改为

for (i = 0 ; i < sizeof(clientSockets)/sizeof(clientSocket[0]) ; i++)

可能会修复段错误。