我正在尝试创建一个客户端服务器井字游戏作为家庭作业。我在单独的函数中设置服务器侦听器和连接,而不是在主程序中。服务器套接字的创建是成功的,但客户端连接失败,我认为这就是导致下面的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"传递给的参数type"socklen_t*"(又名"unsigned int*")[-Wint转换]clientsocket[con_num]=接受(serversocket,(structsockaddr)&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 servern");
}
//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 bindn");
}
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
如果你能向我解释我做错了什么,那将非常有帮助。
编译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手册页上所说的
addrlen参数是一个值-结果参数:调用者必须初始化它以包含addr指向的结构的大小(以字节为单位);返回时,它将包含对等地址的实际大小。
您注意到收到的警告是正确的:
警告:不兼容的整数到指针转换将"int"传递到类型为"socklen_t*"(又名"unsigned int*")的参数[-Wint conversion]clientsocket[con_num]=accept(serversocket,(structsockaddr)&cli_addr、cli_size);
折扣是错误的:
然而,我检查的所有示例都是这样通过的。
如果您看过的所有示例都使用与您类似的代码,那么您迫切需要找到更好的示例。然而,更重要的是,你需要学会依赖文档,最好是作为你的第一追索权,但至少要消除不确定性,比如"这个警告是我应该关心的吗?"(提示:除非你能以其他方式表达基于文档的原因,否则答案总是"是的,我应该关心警告"。)
快速查看accept()
的文档会发现,第三个参数应该是指向变量的指针,该变量包含您传递的地址对象的大小,函数将更新该变量(通过指针)以包含返回的地址的实际长度。相反,您传递的是大小本身,转换为指针几乎肯定会产生无效的大小。事实上,你很幸运,这样你就会得到一个运行时错误,因为另一种选择是你在程序中的某个随机位置默默地产生内存损坏。
注意,bind()
是不同的。它要求您直接传递地址的大小,而不是间接传递。这是合理的,因为它没有理由想要修改大小。