【问题标题】:I'm getting "Segmentation Fault(Core dump)" when i'm running a socket related program当我运行与套接字相关的程序时,我收到“分段错误(核心转储)”
【发布时间】:2019-07-11 23:17:43
【问题描述】:

当导致分段错误时,我已经搜索过,但我无法纠正代码中的错误。我正在使用 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);                
            }   
        }
    }
}

【问题讨论】:

  • 代码中的seg错误发生在哪里?您的编译器中是否打开了警告?您是否在调试模式下运行,以便您可以单步执行以查看每个语句发生了什么?
  • 考虑 IPv4 和 IPv6 的结构大小不同但通过相同指针传递的事实。被调用者知道它得到了什么的唯一方法是通过该大小变量。这些方法也有很多可能会失败,您需要检查文档中描述的错误情况。
  • @ryyker 出于某种原因,对象 master 和 read_fds 显示为 和 FD_SET,FD_INIT 函数将返回一个整数,当我尝试分配一个整数时,我“从不兼容的类型 'void' 分配给 'int' 时出现此错误”

标签: c sockets


【解决方案1】:

崩溃就在这里:

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() 的返回值以确保它返回零/成功,并在它返回非零/错误时优雅地处理它,而不是仅仅假设它总是成功。 (通常,您需要对所有返回成功/失败值的函数调用执行此操作)

【讨论】:

    【解决方案2】:

    根据您的评论,您使用的某些实用程序似乎定义不正确。对于您要拉入项目的任何库,请确保您使用的是正确的(和相应的)头文件。即对于 POSIX 开发,建议使用这个:

    /* According to POSIX.1-2001 */
    #include <sys/select.h>
    

    (More here about that)

    我没有看到您的#include 语句中提到的select.h 文件。

    【讨论】:

    • 这解决了 ,但在运行代码时仍然收到错误“Segmentation fault(Core dumped)”
    猜你喜欢
    • 2020-09-09
    • 1970-01-01
    • 2018-10-13
    • 2013-05-04
    • 2020-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多