在Linux下使用C++编程,Socket监听不会解除绑定。

11

我有一个监听某个端口的Socket。

我向等待该端口(使用accept)的线程发送SIGSTOP信号并终止它。然后我关闭了我正在等待的Socket的文件描述符。但是在下一次运行我的项目时,它不允许我再次监听该端口。

我的程序是在Linux下用C++编写的。

我该怎么办?

我的代码的一些部分如下:

线程1:

void* accepter(void *portNo) {
int newsockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("ERROR opening socket");
}
struct sockaddr_in server;
bzero((char *) & server, sizeof (server));
server.sin_family = AF_INET;
server.sin_port = htons(*(int*) portNo);
server.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr *) & server, sizeof (struct sockaddr_in)) < 0) {
perror("ERROR on binding");
}

listen(sockfd, 50);
while (true) {
struct sockaddr_in client;
socklen_t clientLen = sizeof (struct sockaddr_in);
newsockfd = accept(sockfd, (struct sockaddr *) & client, &clientLen);
if (accepterFlag) {
    break;
}
if (getpeername(newsockfd, (sockaddr *) & client, &clientLen) == -1) {
    perror("getpeername() failed");
}
sem_wait(setSem);
FD_SET(newsockfd, &set);
if (maxFd < newsockfd) {
    maxFd = newsockfd;
}
sem_post(setSem);
}

线程2:

listenerFlag = true;
accepterFlag = true;
sleep(1);
pthread_kill(listenerThread, SIGSTOP);
pthread_kill(accepterThread, SIGSTOP);
close(sockfd);
sem_wait(setSem);
for (int i = 1; i <= maxFd; i++) {
if (FD_ISSET(i, &set)) {
    close(i);
}
}
sem_post(setSem);

谢谢。


也许尝试在接受线程中关闭套接字的文件描述符,因为它正在终止? - Daniel Bingham
1
你确定要发送 SIGSTOP 吗?之后会有人发送 SIGCONT 吗?如果某个(已停止的)线程仍在该套接字上进行 accept 调用,那么我不会感到惊讶,套接字可能无法最终关闭。(你说你也终止了线程,但我没有看到。) - Christopher Creutzig
2个回答

24

你知道吗,套接字在你完成监听后通常会保持一种“悬浮状态”一两分钟,以防止本来发送给先前进程的通信传递到你这里。它被称为“TIME_WAIT”状态。

如果你想重写这种行为,在监听之前使用setsockopt设置SO_REUSEADDR标志来对套接字进行操作。


5
请查看 SO_LINGER。http://www.developerweb.net/forum/archive/index.php/t-2982.html - jfawcett
我知道这在Java里是如此。C++也一样吗? - Shayan
4
没问题,这是一个TCP的问题而不是语言问题,所以它适用于任何地方。 - Colin Newell
为了档案记录,看起来在苹果上您还需要设置SO_REUSEPORT标志:int reusePort = 1; setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &reusePort, sizeof(reusePort)); - Mattijs

1

我认为问题在于您没有正确关闭套接字和/或程序。套接字可能仍然存在于操作系统中。使用类似于nestat -an的命令进行检查。您还应该检查您的进程是否已退出。如果正确结束,它应该已经关闭了您的套接字。

您应该做的是:

  • 使用信号中断您的线程。
  • 当线程被中断时,应在结束之前干净地关闭套接字。
  • 然后您可以从程序中干净地退出。

以上仅供参考。


好的,那么SO_REUSEADDR就是关键 :-) - neuro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接