我正在尝试在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, &le_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()调用注释掉,仍然得到分段错误错误,所以我不认为这是问题。为什么要运行呢?我不希望内存泄漏。谢谢你的帮助。
答案 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