下面是一个类似守护进程的抽象代码。我需要检查我的守护进程是否已经在这里了(如果是,我退出)。然后我关闭绑定的套接字,做一些fork(它们在守护进程重新启动后仍然存在,所以我不希望它们拥有我的绑定套接字)。
int is_me_here()
{
int sck = socket(AF_INET, SOCK_STREAM, 0), temp=1;
struct sockaddr_in addr;
addr.sin_port = htons(1234);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
bzero(addr.sin_zero, 8);
//setsockopt(sck,SOL_SOCKET,SO_REUSEADDR,&temp,sizeof(int)); // #1 HERE?
if ((bind(sck, (struct sockaddr *)(&addr), sizeof(struct sockaddr_in))) < 0){
printf("cannot bind. My daemon is already here\n");
return -1;
}
close(sck);
return 0;
}
void foo(){
int sck = socket(AF_INET, SOCK_STREAM, 0), temp=1, new_sockfd;
struct sockaddr_in addr, cliaddr;
addr.sin_port = htons(1234);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
bzero(addr.sin_zero, 8);
//setsockopt(sck,SOL_SOCKET,SO_REUSEADDR,&temp,sizeof(int)); // #2 HERE?
if ((bind(sck, (struct sockaddr *)(&addr), sizeof(struct sockaddr_in))) < 0){
printf("WTF\n");
return;
}
listen(sck, 5);
socklen_t lenaddr = sizeof(struct sockaddr_in);
while(1){
if ((new_sockfd = accept(sck, (struct sockaddr *)(&cliaddr), &lenaddr)) == -1){
sleep(1);
continue;
}
// ...
close(new_sockfd);
}
}
int main()
{
if (is_me_here() < 0)
return 0;
// some forks. Dont wanna them having the socket binded.
foo();
return 0;
}
据我所知,内核将绑定套接字保存在TIME_WAIT
中。因此,我需要在fork之后再次使用SO_REUSEADDR
进行绑定。但是,应用SO_REUSEADDR
的正确位置在哪里?内核将在is_me_here()
之后将套接字保存在TIME_WAIT
中吗?我不知道listen()
或accept()
之类的。
在我的系统和其他一些系统上,无论我在哪里设置SO_REUSEADDR
,代码都能正常工作。但是我担心其他一些系统会在foo()
中给予我一个bind()
错误。
3条答案
按热度按时间a7qyws3x1#
通常,您总是希望在TCP侦听套接字上设置
SO_REUSEADDR
。如果您没有设置它,如果您的程序关闭,然后在1或2分钟内重新启动,您可以得到一个“地址已在使用中”错误,如果仍然有套接字在TIME_WAIT。
如果您试图启动该程序,而另一个程序已经在侦听该端口,您仍然会收到“地址已在使用”错误。
这也意味着你不需要为了检查而打开一个额外的套接字,只需要打开一次,如果套接字已经被使用,就退出。
mnemlml82#
你必须把标志设置为int型,传递指针和标志的大小。
您可以在UDP和TCP套接字上使用SO_REUSEADDR,就在您创建套接字之后。
kknvjkwl3#
成功初始化套接字后设置它:
这些错误在失败时返回-1,因此您应该为它们设置。
现在设置选项:
现在
bind()
。另请参阅:How do SO_REUSEADDR and SO_REUSEPORT differ?