c - 当我运行与套接字相关的程序时,我收到“分段错误(核心转储)”
问题描述
当导致分段错误时,我用谷歌搜索,但我无法纠正代码中的错误。我正在使用 select 函数来找出哪些文件描述符是可读的。我在 c 和我的套接字编程方面相当新当我们有用于 ipv4 地址长度的宏时,无法理解结构 socklen_t 的用途。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netdb.h>
#define PORT "9034"
int main()
{
fd_set master,read_fds;
int file_descriptor,new_fd,server,yes=1,error,fd_max,i;
char ip[INET_ADDRSTRLEN],data[1024];
struct addrinfo hints,*p;
struct sockaddr_in addr;
socklen_t addrlen; //?
memset(&hints,0,sizeof(struct addrinfo));
FD_ZERO(&master);
FD_ZERO(&read_fds);
hints.ai_family=AF_INET;
hints.ai_socktype=SOCK_STREAM;
hints.ai_protocol=AI_PASSIVE;
file_descriptor=getaddrinfo(NULL,PORT,&hints,&p);
printf("%s",inet_ntop(AF_INET,p->ai_addr,ip,addrlen));
server=socket(p->ai_family,p->ai_socktype,p->ai_protocol);
setsockopt(server,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int));
listen(server,5);
FD_SET(server,&master);
fd_max=server;
while (1)
{
read_fds=master;
select(fd_max+1,&read_fds,NULL,NULL,NULL);
for(i=0;i<fd_max;i++)
{
if(i==server)
{
new_fd=accept(server,(struct sockaddr *)&addr,&addrlen);
FD_SET(new_fd,&master);
printf("Connected to the client %s on socket %d",inet_ntop(AF_INET,(struct sockaddr *)&addr,ip,INET_ADDRSTRLEN),new_fd);
if(new_fd>fd_max)
fd_max=new_fd;
}
else
{
recv(i,data,sizeof(data),0);
printf("%s",data);
}
}
}
}
解决方案
崩溃在这里:
file_descriptor=getaddrinfo(NULL,PORT,&hints,&p);
printf("%s",inet_ntop(AF_INET,p->ai_addr,ip,addrlen));
请注意,在第二行中,您正在取消引用指针p
- 但p
为 NULL 因为getaddrinfo()
失败并且没有将其设置为有效地址,因此尝试取消引用会调用未定义的行为,并且在这种情况下会导致崩溃。
顺便说一句,我能够通过printf()
在程序的各个点插入临时语句并查看打印(或未打印)的内容来调试它。尤其是:
printf("k1\n");
file_descriptor=getaddrinfo(NULL,PORT,&hints,&p);
printf("k2 file_descriptor=%i p=%p\n", file_descriptor, p);
printf("%s",inet_ntop(AF_INET,p->ai_addr,ip,addrlen));
printf("k3\n");
...当我使用这样的代码运行时,我看到了以下输出:
k1
k2 file_descriptor=12 p=0x0
Segmentation fault: 11
...这使问题变得明显 - p 在“k2”行中为 NULL(又名 0x0),并且在“k3”行打印之前发生了崩溃,因此崩溃肯定在您的printf()
调用中,并且由于NULL 指针取消引用。
要修复崩溃,您需要检查 的返回值getaddrinfo()
以确保它返回零/成功,并在它返回非零/错误时优雅地处理它,而不是仅仅假设它总是会成功。(通常,您需要对所有返回成功/失败值的函数调用执行此操作)
推荐阅读
- teamcity - 升级到 2021.1 后运行器不兼容
- java - Netbeans 中的 XML 部署
- ruby - Ruby 类中的继承
- sublimetext3 - 按下 Enter 后没有额外的行 Sublime Text 3
- reactjs - 位置路径名删除反应中错误路径上的图标
- javascript - 获得 TypeError: state.posts 在看似成功的 POST 请求之后不可迭代
- python - 面对 ValueError:尝试使用不受支持的类型转换值(无)(
) 到张量 - python - 使用来自不同数据帧的键重命名和删除列
- .net - 检查是否从 .NET Core 应用程序配置了托管标识
- r - 如何从列中的项目中删除字符?