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

Posted

技术标签:

【中文标题】TCP-IP 套接字 C:尝试连接到服务器套接字时出现错误地址错误【英文标题】:TCP-IP sockets C: Bad address error when trying to connect to server socket 【发布时间】:2019-06-25 01:53:30 【问题描述】:

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

我已经查找了类似的问题,并尽我所能对我的代码进行了调整,比如为 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

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

【问题讨论】:

【参考方案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

如果您要使用cli_addr 结构,则应检查返回的大小是否大于您传入的大小,如果是,则表示地址结构已被截断。

Linux man page 是这么说的

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

【讨论】:

【参考方案2】:

注意您收到的警告是正确的:

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

打折是错误的:

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

如果您查看的所有示例都使用与您类似的代码,那么您迫切需要找到更好的示例。然而,更重要的是,您需要学会依赖文档,最好将其作为您的第一选择,但至少要消除不确定性,例如“我应该关心这个警告吗?” (提示:除非你能以其他方式表达基于文档的理由,否则答案总是“是的,我应该关心警告”。)

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

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

【讨论】:

以上是关于TCP-IP 套接字 C:尝试连接到服务器套接字时出现错误地址错误的主要内容,如果未能解决你的问题,请参考以下文章

c ++ system()挂起使用netcat连接到不同线程中的套接字

连接到服务器时客户端套接字超时

启用 SSL 的网站无法连接到本地 C# Web 套接字服务器

使用 SSH 隧道时无法通过套接字错误连接到本地 MySQL 服务器

循环直到使用 BeginConnect(C# 套接字)连接到服务器

尝试将 node.js unix 套接字客户端连接到 C 程序时出现 EPROTOTYPE 错误