分段故障 - 套接字编程 - C.

时间:2018-06-05 12:00:22

标签: c sockets segmentation-fault

我正在尝试在C中编写echo服务器\客户端模型。我的代码编译但在运行时抛出了分段错误错误[我相信服务器端进程]。在CLion调试环境中进行测试时,服务器进程能够执行accept()系统调用并进入等待状态,直到客户端连接。因此,我认为在客户端进行connect()系统调用之后会发生分段错误错误。

以下是代码的相关摘要(仅限最后一部分 - 不是完整程序):

/* [6] LISTEN FOR CONNECTIONS ON BOUND SOCKET===================================================================== */
struct sockaddr_storage ample;    /* from Beej Guide 5.6 accept() */
socklen_t ample_sz = sizeof(ample);
fd_activeSock = accept(fd_listenSock, (struct sockaddr *)&established_SERV_param, &ample_sz);

if (fd_activeSock == -1)    /* Error checking */
{
    fprintf(stderr, "\nNo forum for communication...\nTERMINATING PROCESS");
    exit(EXIT_FAILURE);
}

printf("\nCommunication Established! What's your sign??");
freeaddrinfo(established_SERV_param);    /* free up memory */

/* [7] ACCEPT A CONNECTION (BLOCKING)============================================================================= */

/* MAIN LOOP====================================================================================================== */
while(1)
{
    bzero(msg_incoming, 16);
    recv(fd_activeSock, msg_incoming, 16, 0);
    printf("%s", msg_incoming);
    send(fd_activeSock, msg_incoming, 16, 0);
}

当我在不同的终端中运行这两个程序时(当然首先是服务器进程),在错误之前运行的最后一个print语句是:

printf("\nCommunication Established! What's your sign??");

错误输出到服务器终端。有一个核心转储;对于未来的问题,有人可以建议一个关于梳理核心转储文件的初学者教程。此外,我运行代码与freeaddrinfo()调用注释掉,仍然得到分段错误错误,所以我不认为这是问题。为什么要运行呢?我不希望内存泄漏。谢谢你的帮助。

2 个答案:

答案 0 :(得分:4)

recv() 没有在缓冲区末尾显式地放置空终止符,但printf()需要一个。

在声明中:

bzero(msg_incoming, 16);
recv(fd_activeSock, msg_incoming, 16, 0);
printf("%s", msg_incoming); 

虽然msg_incoming已归零,但在recv调用中填充时,如果填充了所有16个元素,则无法保证数组的最后一个元素填充了'\ 0 ',将缓冲区保留为非空终止数组。如果发生这种情况,可能会在调用printf()时发生段错误。或者更糟糕的是, a segfault may not occur ,让您相信您的代码运行正常。 (AKA未定义的行为)

修复方法是检查 recv() 的返回值:

ssize_t bytes = recv(fd_activeSock, msg_incoming, 16, 0);
if(bytes <= 0)
{
    //handle error/end of message condition
}
else
{
    msg_incoming[bytes] = '\0';
    printf("%s", msg_incoming);
}

Reading data with a socket 上的其他资料。

答案 1 :(得分:2)

freeaddrinfo(established_SERV_param)

established_SERV_param获取getaddrinfo时应该调用。这里established_SERV_param可能是一个堆栈变量。因此,您试图释放指向堆栈变量的指针。

你的程序中有什么问题。由于freeaddrinfo需要指针,但它是一个变量,因为您在调用&时使用了accept。删除对freeaddrinfo的呼叫可能会解决此问题。

如果上述内容不够,那么了解如何定义/分配msg_incoming非常重要。它不应该是const char数组或由字符串文字初始化,使其成为const。如果是指针,则应使用malloc充分分配内存。

分析核心转储:

使用debug On和优化Off编译代码

gcc -g -O0

然后在gdb中打开核心文件

gdb <executable> <core file>
(gdb) bt 

在上面,bt将显示程序崩溃的后跟踪。您可以通过命令fr 0执行崩溃的功能并打印一些变量。 gdb教程可以找到here