免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2363 | 回复: 8
打印 上一主题 下一主题

[C] TCP并发服务器例子出错,使用线程 [复制链接]

论坛徽章:
1
处女座
日期:2014-11-29 14:47:43
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-10-23 16:26 |只看该作者 |倒序浏览
本帖最后由 Gnixfeng 于 2014-10-23 16:36 编辑

例子是UNP第30章里的例子。源码附在后面。

运行成功是这样子的:运行服务器 $ ./pthread_server 49001和客户:$ ./client localhost 49001 5 10 4000
服务器显示:

客户显示:


错误描述:
               第一种错误情况:运行服务器 $ ./pthread_server 49001和客户:$ ./client localhost 49001 5 10 4000
服务器显示

客户显示

               第二中出错情况:运行服务器 $ ./pthread_server 49001和客户:$ ./client localhost 49001 5 10 4000



               第三中出错情况:运行服务器 $ ./pthread_server 49001和客户:$ ./client localhost 49001 5 10 4000




有时成功,有时错误。我怀疑是不是资源限制的问题。如果把线程换成进程就不会出现这种问题。

想一天了,都没弄清楚。望指教啊!


服务器主程序,包装好的程序都在unp.h中定义了
  1. #include "../lib/unp.h"

  2. int main(int argc, const char *argv[])
  3. {
  4.     int     listenfd, connfd;
  5.     void    sig_int(int);
  6.     void    *doit(void*);
  7.     pthread_t   tid;
  8.     socklen_t   clilen, addrlen;
  9.     struct sockaddr     *cliaddr;

  10.     if (argc == 2){
  11.         listenfd = Tcp_listen(NULL, argv[1], &addrlen);
  12.     }else if(argc == 3){
  13.         listenfd = Tcp_listen(argv[1], argv[2], &addrlen);
  14.     }else
  15.         err_quit("usage:pthraed_server <Host/IPadrress> <service/#port>");
  16.     cliaddr = malloc(addrlen);

  17.     Signal(SIGINT, sig_int);

  18.     for( ; ;)
  19.     {
  20.         clilen = addrlen;
  21.         connfd = Accept(listenfd, cliaddr, &clilen);
  22.         printf("Connecting form %s\n",
  23.                 sock_ntop((SA *)cliaddr, clilen));
  24.         
  25.         pthread_create(&tid, NULL, &doit, (void*)connfd);
  26.     }
  27.     return 0;
  28. }
  29. void *
  30. doit(void *arg)
  31. {
  32.         void        web_child(int);

  33.         pthread_detach(pthread_self());
  34.     //printf("connfd: %d\n", (int)arg);
  35.         web_child((int)arg);
  36.         Close((int) arg);
  37.     //printf("close %d\n", (int)arg);
  38.         return(NULL);
  39. }
  40. /* end serv06 */

  41. void
  42. sig_int(int signo)
  43. {
  44.         void        pr_cpu_time(void);

  45.         pr_cpu_time();
  46.         exit(0);
  47. }
复制代码
web_child函数,MAXLINE等都已经在头文件unp.h中定义
  1. #include "unp.h"

  2. #define MAXN 16384

  3. void web_child(int connfd)
  4. {
  5.     int     ntowrite;
  6.     ssize_t nread;
  7.     char    line[MAXLINE], result[MAXN];

  8.     for ( ; ;){
  9.         if ((nread = Readline(connfd, line, MAXLINE)) == 0)
  10.             return;

  11.         ntowrite = atoi(line);
  12.         if (ntowrite <= 0 || ntowrite > MAXN)
  13.             err_quit("client request for %d bytes", ntowrite);

  14.         Writen(connfd, result, ntowrite);
  15.     }
  16. }
复制代码
客户程序:
  1. #include "unp.h"

  2. #define MAXN 16384

  3. int main(int argc, const char *argv[])
  4. {
  5.     int     i, j, fd, nchildren, nconnects, nbytes, status;
  6.     pid_t   pid;
  7.     ssize_t n;
  8.     char    request[MAXLINE], reply[MAXN];

  9.     if (argc != 6)
  10.         err_quit("usage: client <Host/IP> <#Port> <#children>"
  11.                 " <#connect> <#bytes/request>");

  12.     nchildren = atol(argv[3]);
  13.     nconnects = atol(argv[4]);
  14.     nbytes = atol(argv[5]);
  15.     snprintf(request, sizeof(request), "%d\n", nbytes);

  16.     printf("nchildren = %d, nconnects = %d\n", nchildren, nconnects);
  17.     for(i = 0; i < nchildren; i++){
  18.         if ((pid = fork()) == 0){
  19.             for(j = 0; j < nconnects; j++)
  20.             {
  21.                 fd = tcp_connect(argv[1], argv[2]);

  22.                 Write(fd, request, strlen(request));

  23.                 if ((n = readn(fd, reply, nbytes)) != nbytes)
  24.                     err_quit("server returned %d bytes", n);

  25.                 Close(fd);
  26.                 printf("close %d\n", fd);
  27.             }
  28.             printf("child %d done\n", i);
  29.             exit(0);
  30.         }
  31.     }

  32.     for( i = 0; i < nchildren; i++)
  33.         if (waitpid(-1, &status, 0) < 0)
  34.             err_sys("waitpid error");

  35.     return 0;
  36. }
复制代码

server.png (6.41 KB, 下载次数: 35)

server.png

client.png (12.12 KB, 下载次数: 34)

client.png

server.png (6.41 KB, 下载次数: 33)

server.png

论坛徽章:
1
处女座
日期:2014-11-29 14:47:43
2 [报告]
发表于 2014-10-23 16:38 |只看该作者
第一种错误的图片泡到后面了,倒数2、3张,编辑不了

论坛徽章:
324
射手座
日期:2013-08-23 12:04:38射手座
日期:2013-08-23 16:18:12未羊
日期:2013-08-30 14:33:15水瓶座
日期:2013-09-02 16:44:31摩羯座
日期:2013-09-25 09:33:52双子座
日期:2013-09-26 12:21:10金牛座
日期:2013-10-14 09:08:49申猴
日期:2013-10-16 13:09:43子鼠
日期:2013-10-17 23:23:19射手座
日期:2013-10-18 13:00:27金牛座
日期:2013-10-18 15:47:57午马
日期:2013-10-18 21:43:38
3 [报告]
发表于 2014-10-23 16:42 |只看该作者
应该是服务端write之后马上close所致

论坛徽章:
1
处女座
日期:2014-11-29 14:47:43
4 [报告]
发表于 2014-10-23 16:51 |只看该作者
回复 3# hellioncu
在web_child()函数里面是一个循环

    for ( ; {
        if ((nread = Readline(connfd, line, MAXLINE)) == 0)
            return;

        ntowrite = atoi(line);
        if (ntowrite <= 0 || ntowrite > MAXN)
            err_quit("client request for %d bytes", ntowrite);

        Writen(connfd, result, ntowrite);
    }
这也是我所不理解的,看上去web_child()应该会在err_quit()上退出,但是err_quit()中调用了exit()函数,按理应该整个进程都终止了。但是实际不是这样,doit()中的Close依然会执行。

   

论坛徽章:
1
处女座
日期:2014-11-29 14:47:43
5 [报告]
发表于 2014-10-23 16:57 |只看该作者
回复 3# hellioncu
如果把服务器换成创建进程,就不会出现错误。
  1. for( ;  ; )
  2.     {
  3.         clilen = addlen;
  4.         if ((connfd = accept(listenfd, cliaddr, &clilen)) < 0){
  5.             if (errno == EINTR)
  6.                 continue;
  7.             else
  8.                 err_sys("accept error");
  9.         }
  10.         /*
  11.         printf("Connecting form %s\n",
  12.                 sock_ntop((SA *)cliaddr, clilen));
  13.                 */
  14.         if ((childpid = fork()) == 0){
  15.             Close(listenfd);
  16.             web_child(connfd);
  17.             exit(0);
  18.         }else if(childpid < 0)
  19.             err_sys("fork error");

  20.         Close(connfd);
  21.     }
复制代码

论坛徽章:
324
射手座
日期:2013-08-23 12:04:38射手座
日期:2013-08-23 16:18:12未羊
日期:2013-08-30 14:33:15水瓶座
日期:2013-09-02 16:44:31摩羯座
日期:2013-09-25 09:33:52双子座
日期:2013-09-26 12:21:10金牛座
日期:2013-10-14 09:08:49申猴
日期:2013-10-16 13:09:43子鼠
日期:2013-10-17 23:23:19射手座
日期:2013-10-18 13:00:27金牛座
日期:2013-10-18 15:47:57午马
日期:2013-10-18 21:43:38
6 [报告]
发表于 2014-10-23 17:02 |只看该作者
Gnixfeng 发表于 2014-10-23 16:57
回复 3# hellioncu
如果把服务器换成创建进程,就不会出现错误。


doit中Close((int) arg);之前加个usleep(10000);试试

论坛徽章:
1
处女座
日期:2014-11-29 14:47:43
7 [报告]
发表于 2014-10-23 17:19 |只看该作者
回复 6# hellioncu


    没有用哦,还是那样

论坛徽章:
1
处女座
日期:2014-11-29 14:47:43
8 [报告]
发表于 2014-10-23 21:58 |只看该作者
回复 7# Gnixfeng
哦,可能是我用错readline()的非线程安全的版本了

   

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
9 [报告]
发表于 2014-10-30 07:54 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP