我有以下使用Linux套接字的示例代码:
void serve_request(int newsockfd)
{
char buffer[256];
int n;
/*if connection established then start communicating*/
bzero(buffer, 256);
n=read(newsockfd, buffer, 255);
if(n<0)
{
perror("Error reading from socket");
}
printf("Here is the message: %s\n",buffer);
/*write response to the client*/
n=write(newsockfd,"I got your message", 18);
if(n<0)
{
perror("Error writing to socket");
exit(1);
}
//close(newsockfd);
}
int main(int argc, char* argv)
{
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
/*first call to socket function*/
sockfd=socket(AF_INET, SOCK_STREAM, 0);
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0);
if(sockfd<0)
{
perror("Error opening socket");
exit(1);
}
/*initialize socket structure*/
bzero((char*)&serv_addr, sizeof(serv_addr));
portno=5001;
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=INADDR_ANY;
serv_addr.sin_port=htons(portno);
/*now bind the host address using bind() call.*/
if(bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr))<0)
{
perror("Error on binding");
exit(1);
}
/*now start listening for the clients, here process will
go in sleep mode and will wait for the incoming connection*/
listen(sockfd, 5);
clilen=sizeof(cli_addr);
while(1)
{
/*accept actual connection from the client*/
newsockfd=accept(sockfd, (struct sockaddr*)&cli_addr, &clilen);
if(newsockfd<0)
{
perror("Error on accept");
exit(1);
}
serve_request(newsockfd);
}
return 0;
}
这一切都很好。当我执行./a.out
时,它启动套接字服务器并等待客户端。当我使用^C
退出代码时,它会停止并返回提示。
但是,如果代码符合方法//close(newsockfd);
中的最后一行(void serve_request(int newsockfd)
)未注释且客户端已经过去,则按下^C
并再次调用服务器使用./a.out
,它会显示Error on binding: Already in use
。
但是如果我编写了最后一行注释的代码,那么它工作正常,这意味着我可以立即用./a.out
调用服务器并重新启动服务器,而无需像上一个案例那样等待一段时间
有人可以正确处理这个问题。 任何帮助深表感谢。谢谢。
答案 0 :(得分:2)
当您打开套接字时,您分配了一个操作系统资源,并告诉您要重用套接字地址的o / s taht。
程序结束时没有自动清理。资源仍然分配。
取消注释close()
并养成总是释放任何和所有资源的习惯,无论是内存,套接字,互斥体还是其他什么。
答案 1 :(得分:0)
你的问题与close()没什么关系。我怀疑你只是在调用之间等待了不同的时间。
1)您正在调用setsockopt错误,因此您尝试设置的选项无效。这是一个工作调用的例子:
int optval = 1; //enable option
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) {
perror("setsockopt()");
exit(1);
}
请注意,第三个参数是指针,对于任何合理的调用都是非可选的。 man setsockopt :
大多数套接字级选项都使用int参数进行optval。对于 setsockopt(),参数应该是非零的 启用布尔选项,如果要禁用该选项,则为零。
2)您没有检查setsockopt()
的返回值,因此找不到错误的希望很小。
3)完成后,请关闭newsockfd
。在退出程序之前也要关闭sockfd
。
摘要:始终检查所有系统调用的返回值。为手册页上列出的所有返回值做好准备。在所有执行路径中释放/关闭所有已分配的资源。
PS。有点讽刺的是,编译代码所需的所有#include
语句都是正确问题的一部分。
答案 2 :(得分:0)
您应该设置SO_REUSEADDR。你做到了 - 但不正确。这是如何正确地做到这一点:
/* SO_REUSEADDR allows a new server to be started
* on the same port as an existing server that is
* bound to the wildcard address, as long as each
* instance binds a different local IP address.
* This is common for a site hosting multiple HTTP
* servers using the IP alias technique */
int reuseaddr_on = 1;
if( setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR,
&reuseaddr_on, sizeof( reuseaddr_on)) < 0)
{
// log
}
请务必在调用bind()
之前设置SO_REUSEADDR选项。