TCP-IP 套接字 C:尝试连接到服务器套接字时出现错误地址错误
TCP-IP sockets C: Bad address error when trying to connect to server socket
我正在尝试创建客户端-服务器井字游戏作为家庭作业。我在单独的函数中设置服务器监听器和连接,而不是在主程序中。服务器套接字创建成功,但客户端连接失败,我认为这是导致随后的段错误的原因。
我已经查找过类似的问题并尽可能地调整我的代码,比如为 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 类型时收到警告。
*warning: incompatible integer to pointer conversion passing 'int' to parameter of
type 'socklen_t *' (aka '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);
我在运行程序后得到的是:
Error: : Bad Address
Error: : Bad Address
Segmentation fault: 11
如果你能向我解释我做错了什么,那将非常有帮助。
您注意到收到的警告是对的:
warning: incompatible integer to pointer conversion passing 'int' to
parameter of type 'socklen_t *' (aka 'unsigned int *')
[-Wint-conversion] clientsocket[con_num] = accept(serversocket,(struct
sockaddr ) &cli_addr,cli_size);
你打折错了:
However, all the examples I checked pass it like this.
如果您看过的所有示例都使用与您的代码类似的代码,那么您迫切需要找到更好的示例。然而,更重要的是,您需要学会依赖 文档,最好将其作为您的第一资源,但至少可以消除不确定性,例如 "is this warning something I should care about?"(提示:直到和除非您可以表达基于文档的原因,否则答案总是 "yes, I should care about warnings"。)
快速查看 the docs for accept()
会发现第三个参数应该是一个 指针 指向一个变量 包含 您传递的地址对象的大小,函数将更新该变量(通过指针)以包含返回地址的实际长度。您改为传递大小本身,并且转换为指针几乎肯定会产生无效指针。你真的很幸运它确实如此,所以你会得到一个运行时错误,因为另一种选择是你在程序的某个随机位置默默地产生内存损坏。
请注意 bind()
是不同的。它要求您直接传递地址的大小,而不是间接传递。这是明智的,因为它没有理由要修改大小。
I get a warning when compiling about cli_size type.
*warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'socklen_t *' (aka 'unsigned int *') [-Wint-conversion] clientsocket[con_num] = accept(serversocket,(struct sockaddr ) &cli_addr,cli_size);
However, all the examples I checked pass it like this
不,他们没有。如果他们这样做,他们在编译时会得到与您相同的错误。
这是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 所说的
The addrlen argument is a value-result argument: the caller must initialize it to contain the size (in bytes) of the structure pointed to by addr; on return it will contain the actual size of the peer address.
我正在尝试创建客户端-服务器井字游戏作为家庭作业。我在单独的函数中设置服务器监听器和连接,而不是在主程序中。服务器套接字创建成功,但客户端连接失败,我认为这是导致随后的段错误的原因。
我已经查找过类似的问题并尽可能地调整我的代码,比如为 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 类型时收到警告。
*warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'socklen_t *' (aka '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);
我在运行程序后得到的是:
Error: : Bad Address
Error: : Bad Address
Segmentation fault: 11
如果你能向我解释我做错了什么,那将非常有帮助。
您注意到收到的警告是对的:
warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'socklen_t *' (aka 'unsigned int *') [-Wint-conversion] clientsocket[con_num] = accept(serversocket,(struct sockaddr ) &cli_addr,cli_size);
你打折错了:
However, all the examples I checked pass it like this.
如果您看过的所有示例都使用与您的代码类似的代码,那么您迫切需要找到更好的示例。然而,更重要的是,您需要学会依赖 文档,最好将其作为您的第一资源,但至少可以消除不确定性,例如 "is this warning something I should care about?"(提示:直到和除非您可以表达基于文档的原因,否则答案总是 "yes, I should care about warnings"。)
快速查看 the docs for accept()
会发现第三个参数应该是一个 指针 指向一个变量 包含 您传递的地址对象的大小,函数将更新该变量(通过指针)以包含返回地址的实际长度。您改为传递大小本身,并且转换为指针几乎肯定会产生无效指针。你真的很幸运它确实如此,所以你会得到一个运行时错误,因为另一种选择是你在程序的某个随机位置默默地产生内存损坏。
请注意 bind()
是不同的。它要求您直接传递地址的大小,而不是间接传递。这是明智的,因为它没有理由要修改大小。
I get a warning when compiling about cli_size type.
*warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'socklen_t *' (aka 'unsigned int *') [-Wint-conversion] clientsocket[con_num] = accept(serversocket,(struct sockaddr ) &cli_addr,cli_size);
However, all the examples I checked pass it like this
不,他们没有。如果他们这样做,他们在编译时会得到与您相同的错误。
这是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 所说的
The addrlen argument is a value-result argument: the caller must initialize it to contain the size (in bytes) of the structure pointed to by addr; on return it will contain the actual size of the peer address.