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++)
可能会修复段错误。
所以我有一个用 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++)
可能会修复段错误。