TCP-IP套接字C:尝试连接到服务器套接字时出现错误的地址错误

时间:2019-01-31 15:00:59

标签: c sockets tcp segmentation-fault client-server

我正在尝试创建一个客户端-服务器井字游戏作为家庭作业。我在单独的功能中而不是在主程序中设置服务器侦听器和连接。服务器套接字创建成功,但是客户端连接失败,我认为是导致随后出现段错误的原因。

我已经查找了类似的问题,并尽可能地对代码进行了调整,例如为sizeof(cli_addr)设置变量,而不是直接将其传递给accept()。我不知道为什么它不起作用。

这是建立连接的功能

void setup_connections(int serversocket,int *clientsocket,int portnum){
int cli_size,con_num = 0;
struct sockaddr_in cli_addr;

//server is listening for clients
listen(serversocket,5);

while(con_num<2){


    cli_addr.sin_family = AF_INET;
    cli_addr.sin_addr.s_addr = INADDR_ANY;
    cli_addr.sin_port = htons(portnum);

    //accept connection while creating client socket
    cli_size = sizeof(cli_addr);
    clientsocket[con_num] = accept(serversocket,(struct sockaddr *) &cli_addr,cli_size);

    if(clientsocket[con_num]<0){
        perror("Error: ");
    }

    con_num++;

    }
}

编译cli_size类型时会收到警告。

  

*警告:指针转换不兼容的整数,将“ int”传递给参数         输入“ socklen_t *”(又名“ unsigned int *”)[-Wint-conversion]           clientsocket [con_num] = accept(serversocket,(struct sockaddr )&cli_addr,cli_size);

但是,我检查的所有示例都是这样通过的。

这是设置服务器套接字的功能。

int setup_server(int portnum){
int serversocket,serv_bind;
struct sockaddr_in server_addr;


serversocket = socket(AF_INET, SOCK_STREAM, 0);
if(serversocket<0){
    printf("Failed to create server\n");
}

//set up server info
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(portnum); //port number given by user

//link server address to socket
serv_bind = bind(serversocket,(struct sockaddr *) &server_addr,sizeof(server_addr));
if(serv_bind<0){
    printf("Failed to bind\n");
}

return serversocket;
}

这是main.c中调用它们的代码:

int portnum,serversocket, clientsocket[2]; //sockets


portnum = atoi(argv[1]);
if(argc < 2){
    printf("Port number not given");
}

//create sockets
serversocket = setup_server(portnum);
setup_connections(serversocket,clientsocket);

运行程序后得到的是:

  

错误::地址错误

     

错误::地址错误

     

分段错误:11

如果您可以向我解释我做错了什么,那将非常有帮助。

2 个答案:

答案 0 :(得分:1)

  

编译cli_size类型时会收到警告。

     

*警告:指针转换不兼容的整数,将'int'传递给类型为'socklen_t *'(又名'unsigned int *')的参数[-Wint-conversion] clientsocket [con_num] = accept(serversocket,(struct sockaddr) &cli_addr,cli_size);

     

但是,我检查的所有示例都通过了这样的操作

不,他们没有。如果这样做,它们在编译时将得到与您相同的错误。

这是accept

的原型
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//                                                      ^ Note the asterisk

您可以清楚地看到它期望指向socklen_t的指针。您的socklen_t行应如下所示:

accept

如果要使用clientsocket[con_num] = accept(serversocket,(struct sockaddr *) &cli_addr,&cli_size); // ^ Note the pointer indirection 结构,则应检查返回的大小是否大于传递的大小,因为如果是,则表示地址结构已被截断。

Linux man page所说的

  

addrlen参数是一个值结果参数:调用者必须对其进行初始化,以包含addr指向的结构的大小(以字节为单位);返回时,它将包含对等地址的实际大小。

答案 1 :(得分:0)

您应该注意收到的警告:

  

警告:指针转换不兼容的整数,将“ int”传递给   'socklen_t *'类型的参数(又名'unsigned int *')   [-Wint-conversion] clientsocket [con_num] = accept(serversocket,(struct   sockaddr)&cli_addr,cli_size);

打折时您错了:

  

但是,我检查的所有示例都是这样通过的。

如果您查看的所有示例都使用与您类似的代码,那么您迫切需要找到更好的示例。但是,更重要的是,您需要学会依赖文档,最好是将其作为您的第一个求助手段,但是至少要消除不确定性,例如“此警告是否值得我关注?” (提示:直到并且除非您可以表达基于文档的原因,否则答案始终是“是,我应该注意警告”。)

快速查看the docs for accept()会发现,第三个参数应该是指向包含所传递地址对象大小的变量 指针 ,该函数将更新该变量(通过指针)以包含返回地址的实际长度。相反,您传递的是大小本身,几乎可以肯定,转换为指针将产生无效的指针。您实际上很幸运,它确实这样做了,所以您遇到了运行时错误,或者,您可以在程序中某个随机位置静默地产生内存损坏。

请注意,bind()是不同的。它要求您直接而不是间接传递地址的大小。这是明智的,因为没有理由要修改大小。