LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1447|回复: 5

关闭监听套接字是否会让accept()返回?

[复制链接]
发表于 2005-1-23 01:51:14 | 显示全部楼层 |阅读模式
在netbsd下试了,在另外一个线程或者信号响应事件中关闭监听套接字,accept()也不会返回。
为什么呢 :confused:
测试代码如下:

  1. // listen.cpp
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include <unistd.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <arpa/inet.h>
  8. #include <netinet/in.h>
  9. #include <pthread.h>
  10. #include <stdio.h>

  11. struct control
  12. {
  13.         int sock;
  14.         int stop;
  15. };

  16. void *run(void *arg)
  17. {
  18.         control *ctrl = (control*)arg;
  19.         while (!ctrl->stop) {
  20.                 sockaddr_in addr;
  21.                 memset(&addr, 0, sizeof(addr));
  22.                 socklen_t addr_len = sizeof(addr);
  23.                 int conn = accept(ctrl->sock, (sockaddr*)&addr, &addr_len);
  24.                 if (ctrl->stop) {
  25.                         break;
  26.                 }
  27.                 if (conn != -1) {
  28.                         close(conn);
  29.                 }
  30.         }
  31.         return NULL;
  32. }

  33. void stop_thread(control *ctrl)
  34. {
  35.         printf("closing socket...\n");
  36.         ctrl->stop = 1;
  37.         close(ctrl->sock);
  38. }

  39. int main(int argc, char *argv[])
  40. {
  41.         if (argc != 2) {
  42.                 printf("usage: %s <port>\n", argv[0]);
  43.                 return -1;
  44.         }
  45.         unsigned short port = atoi(argv[1]);
  46.        
  47.         sockaddr_in addr;
  48.         memset(&addr, 0, sizeof(addr));
  49.         addr.sin_family = AF_INET;
  50.         addr.sin_addr.s_addr = INADDR_ANY;
  51.         addr.sin_port = htons(port);

  52.         int fd = socket(AF_INET, SOCK_STREAM, 0);
  53.         bind(fd, (sockaddr*)&addr, sizeof(addr));
  54.         listen(fd, 5);

  55.         pthread_t child = 0;
  56.         control *ctrl = new control;
  57.         ctrl->sock = fd;
  58.         ctrl->stop = 0;
  59.         pthread_create(&child, NULL, run, ctrl);

  60.         sleep(3);
  61.         stop_thread(ctrl);
  62.         pthread_join(child, NULL);
  63.         delete ctrl;

  64.         return 0;
  65. }
复制代码
发表于 2005-2-2 21:33:22 | 显示全部楼层
大部分的linux内核对象都有引用计数,只有当计数值为0时,才将对象删除,套接口也是一样的,当你创建新线程时,打开的套接口引用数加1,close套接口先将引用数减1,如果引用数为0,删除套接口,大于0则什么也不干。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-2-3 17:25:12 | 显示全部楼层
我认为线程和套接字的引用计数没有关系。
回复 支持 反对

使用道具 举报

发表于 2005-2-6 20:47:56 | 显示全部楼层
JBug所说的,我也听过!
回复 支持 反对

使用道具 举报

发表于 2005-2-7 14:01:30 | 显示全部楼层
you should know , accept() return in this condition that the TCP 3 handheld finish,that is to say, when connection is established ,first , at client end ,connect() return ,then sends a ACK, which cause  accept()  return at server end.
    the above sir is right, kernel maintain a count for Socket descriptor,if you spawn several threads ,close one just decrease one from the count for the specified descriptor,so ,you have to figure it out by yourself.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-2-21 21:09:42 | 显示全部楼层
经过试验,在另外一个线程中对监听套接字调用shutdown可以使得accept返回,但是在linux和netbsd下略有不同。

  1.           linux2.4.26                netbsd2.0         
  2. SHUT_WR     accept阻塞                 accept返回(errno==ECONNABORTED)
  3. SHUT_RD     accept返回(errno==EINVAL)  accept阻塞
  4. SHUT_RDWR   accept返回(errno==EINVAL)  accept返回(errno==ECONNABORTED)
复制代码


不了解对于监听套接字执行shutdown的行为在特定操作系统上是否有约定。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表