Chinaunix首页 | 论坛 | 博客
  • 博客访问: 480578
  • 博文数量: 111
  • 博客积分: 2332
  • 博客等级: 大尉
  • 技术积分: 1187
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-29 11:22
文章分类

全部博文(111)

文章存档

2013年(9)

2012年(28)

2011年(17)

2010年(28)

2009年(29)

我的朋友

分类: C/C++

2013-05-08 19:16:51

今天看tcp/ip卷1,看到了2msl等待状态那里,就想知道是不是linux和书上写的一样,如果在客户端有连接的情况下,我快速的重启服务两遍,服务是重启不起来的。(感觉实际上不是这样的,所以就做了一个测试)
服务端代码:

点击(此处)折叠或打开

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <sys/socket.h>
  5. #include <netinet/in.h>
  6. #include <sys/epoll.h>

  7. int port = 9112;
  8. int MAX_EVENTS = 10;

  9. int main() {
  10.   int sockfd;
  11.   sockfd = socket(AF_INET, SOCK_STREAM, 0);
  12.   struct sockaddr_in servaddr, cliaddr;
  13.   memset(&servaddr, \'\\0\', sizeof(struct sockaddr_in));
  14.   servaddr.sin_family = AF_INET;
  15.   servaddr.sin_addr.s_addr = htons(INADDR_ANY);
  16.   servaddr.sin_port = htons(port);
  17.   bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr));
  18.   listen(sockfd, SOMAXCONN);
  19.   int cliaddr_len = sizeof(cliaddr);
  20.   char *buf = malloc(256);

  21.   int nfds;
  22.   struct epoll_event ev, events[MAX_EVENTS];
  23.   ev.events = EPOLLIN;
  24.   ev.data.fd = sockfd;
  25.   int epollfd = epoll_create(10);
  26.   if (epollfd == -1) {
  27.     perror(\"epoll_create\");
  28.     exit(0);
  29.   }
  30.   if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev) == -1) {
  31.     perror(\"epoll_ctl: listen_sock\");
  32.     exit(0);
  33.   }

  34.   int i;
  35.   int newfd_mark;
  36.   int num;
  37.   while(1) {
  38.     memset(buf, \'\\0\', 256);
  39.     nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
  40.     if (nfds == -1) {
  41.       perror(\"epoll_pwait\");
  42.       exit(0);
  43.     }
  44.     for (i=0; i<nfds; ++i) {
  45.       int clifd;
  46.       if (events[i].data.fd == sockfd) { // 有新的连接
  47.         clifd = accept(sockfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
  48.         newfd_mark = 1;
  49.       }
  50.       else {
  51.         clifd = events[i].data.fd;
  52.         newfd_mark = 0;
  53.       }
  54.       num = read(clifd, buf, 256);
  55.       printf(\"111 num is %dbbbb\\n\", num);
  56.       if (num <= 0) { // 对方关闭了连接,将close这个sock,将这个sock对应的event从eventlist中去掉
  57.         printf(\"in num < 0\\n\");
  58.         if (epoll_ctl(epollfd, EPOLL_CTL_DEL, clifd, NULL) == -1) {
  59.           perror(\"epoll_ctl: listen_sock\");
  60.         }
  61.         printf(\"close fd %d\\n\", clifd);
  62.         //close(clifd);
  63.         shutdown(clifd, SHUT_RDWR);
  64.         continue;
  65.       }

  66.       printf(\"num is %d\\n\", num);
  67.       write(clifd, buf, 256);
  68.       printf(\"recv is %s\\n\", buf);
  69.       if (newfd_mark == 1) { // 新来的连接,把这个连接增加进eventlist
  70.         struct epoll_event ev;
  71.         ev.events = EPOLLIN;
  72.         ev.data.fd = clifd;
  73.         if (epoll_ctl(epollfd, EPOLL_CTL_ADD, clifd, &ev) == -1) {
  74.           perror(\"epoll_ctl: listen_sock\");
  75.         }
  76.       }
  77.     }
  78.   }
  79.   free(buf);
  80.   close(sockfd);
  81.   return 0;
  82. }

客户端代码

点击(此处)折叠或打开

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <sys/socket.h>
  5. #include <netinet/in.h>
  6. #include <arpa/inet.h>



  7. int main() {
  8.   int sockfd;
  9.   sockfd = socket(AF_INET, SOCK_STREAM, 0);
  10.   struct sockaddr_in servaddr, selfaddr;
  11.   memset(&servaddr, \'\\0\', sizeof(struct sockaddr_in));
  12.   servaddr.sin_family = AF_INET;
  13.   servaddr.sin_port = htons(9112);
  14.   inet_pton(AF_INET, \"127.0.0.1\", &servaddr.sin_addr);
  15.   // 客户端自己帮顶端口
  16.   selfaddr.sin_family = AF_INET;
  17.   selfaddr.sin_port = htons(12306);
  18.   selfaddr.sin_addr.s_addr = htons(INADDR_ANY);
  19.   bind(sockfd, (const struct sockaddr *)&selfaddr, sizeof(selfaddr));

  20.   connect(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr));
  21.   char *content = \"hello world\\n\";
  22.   char *recvbuf = (char *)malloc(256);
  23.   memset(recvbuf, \'\\0\', 256);
  24.   write(sockfd, content, strlen(content));
  25.   read(sockfd, recvbuf, 256);
  26.   printf(\"000 %s\", recvbuf);
  27.   sleep(10);
  28.   memset(recvbuf, \'\\0\', 256);
  29.   write(sockfd, content, strlen(content));
  30.   read(sockfd, recvbuf, 256);
  31.   printf(\"%s\", recvbuf);
  32.   close(sockfd);
  33.   return 0;
  34. }

测试的时候首先测试客户端主动关闭,测试客户端程序里面没有sleep那行
第一次运行test_c,然后sudo netstat -npa | grep 9112,可以看到
tcp        0      0 0.0.0.0:9112                0.0.0.0:*                   LISTEN      10344/./test_s     
tcp        0      0 127.0.0.1:12306             127.0.0.1:9112              TIME_WAIT   -
这说明已经在TIME_WAIT状态了,并且过了一段时间之后第二行TIME_WAIT没有了,说明过了2msl了。
如果连续运行两次test_c,发现第二次运行的时候,客户端的端口变了
tcp        0      0 0.0.0.0:9112                0.0.0.0:*                   LISTEN      10344/./test_s     
tcp        0      0 127.0.0.1:59667             127.0.0.1:9112              TIME_WAIT   -                  
tcp        0      0 127.0.0.1:12306             127.0.0.1:9112              TIME_WAIT   -  
说明linux不是像tcp/ip书里说的那样,没法运行,而是强制换了一个端口,即使bind了一个端口也没用

然后测试服务端主动关闭
如果在客户端的两次发送数据之间加上sleep(10),同时在这期间,将服务端ctrl+c掉,然后在重新启动,结果发现还能启动起来,但是如果用netstat看一下会发现
tcp        0      0 0.0.0.0:56321               0.0.0.0:*                   LISTEN      10781/./test_s 
说明服务端端口号也会变,不管bind和listen的是哪个

ps:在测试服务端主动关闭的时候在把服务端ctrl+c之后,sleep之后的write的信息还能还能被服务端再给回显回来,不知道是为什么。
阅读(6981) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

bo83622013-05-16 14:26:43

C我每没看懂,我用python写了个socket,测试是这样的.
服务端主动关闭,然后快速重起,会提示端口已经占用。
是不是C有什么socket选项之类的,