Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1670365
  • 博文数量: 695
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4027
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-20 21:22
文章分类

全部博文(695)

文章存档

2018年(18)

2017年(74)

2016年(170)

2015年(102)

2014年(276)

2013年(55)

分类: 网络与安全

2014-03-27 16:52:15

多线程并发,处理长连接或者耗时网络操作,提高并发服务效率,相对于select,epoll模型来说,理解简单,适用于单服务器简单负载。


Linux多线程并发网络编程代码 
 /* sokcet_thread.c
编译:
   gcc -g -o socket_thread socket_thread.c -lpthread
*/


点击(此处)折叠或打开

  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <netinet/in.h>
  4. #include <arpa/inet.h>
  5. #include <unistd.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <signal.h>
  10. #include <pthread.h>
  11. #define PORT 9999
  12. #define MAXSOCKFD 10
  13. void *process_client( void *pdata );
  14. void handle_sigcld(int signo);
  15. struct targs{
  16.     int sockfd; // socket id
  17.     pthread_t tid; // 线程id
  18.     char *ip;
  19.     int timeout;
  20. };
  21. int main( int argc, char *argv[] )
  22. {
  23.     int sockfd, connfd;
  24.     struct sockaddr_in servaddr, cliaddr;
  25.     socklen_t cliaddr_len;
  26.     fd_set readfds;
  27.     char buffer[256];
  28.     char msg[] = "Welcome to server!";
  29.     if ( (sockfd=socket(AF_INET,SOCK_STREAM,0))<0 )
  30.     {
  31.         perror("socket");
  32.         return 1;
  33.     }
  34.     bzero(&servaddr, sizeof(servaddr));
  35.     servaddr.sin_family = AF_INET;
  36.     servaddr.sin_port = htons(PORT);
  37.     servaddr.sin_addr.s_addr = htonl( INADDR_ANY );
  38.     int reuse = 1;
  39.     if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
  40.                 &reuse, sizeof(int)) < 0){
  41.         perror("setsockopt error");
  42.         return 1;
  43.     }
  44.     if ( bind(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr) ) != 0 )
  45.     {
  46.         perror("connetc");
  47.         return 1;
  48.     }
  49.     if ( listen(sockfd,5) != 0 )
  50.     {
  51.         perror("listen");
  52.         return 1;
  53.     }
  54.     //允许中断退出
  55. #if 0
  56.     signal(SIGCLD, SIG_IGN); /* now I don't have to wait()! */
  57. #else
  58.     signal(SIGCLD, handle_sigcld); /* 处理中断信息*/
  59. #endif
  60.     while (1)
  61.     {
  62.         cliaddr_len = sizeof( struct sockaddr);
  63.         connfd = accept(sockfd, (struct sockaddr*)&cliaddr,&cliaddr_len );
  64.         if (connfd < 0 ){
  65.             perror("accept");
  66.             continue;
  67.         }
  68.         /*新的连接,启动一个线程处理:
  69.          其实这里可以将线程ID保存起来,以便主进程对其进行管理,比如进程退出
  70.          时,对所以线程进行销毁,这里暂时不用了,简单点吧。
  71.          1,如果要实现可以将pthreadArgs,压入一个全局链表,对每一个线程进行管理,
  72.          2,如果需要传入一些全局配置信息到子线程中,可以通过pthreadArgs结构体参数传入
  73.            如果有些参数需要读写,还需要做线程间互斥。*/
  74.         struct targs *pthreadArgs = (struct targs*)malloc(sizeof(struct targs) );
  75.         pthreadArgs->sockfd = connfd;
  76.         pthread_t pid = 0;
  77.         int pthread = pthread_create(&pid, NULL, process_client, (void *)pthreadArgs);
  78.         if ( pthread != 0 ){
  79.             perror("create thread");
  80.         }else{
  81.             pthreadArgs->tid = pid;
  82.             //加入全局链表,方便管理
  83.         }
  84.     }
  85.     return 0;
  86. }
  87. /* 处理子线程 */
  88. void *process_client( void *pdata )
  89. {
  90.     char *preaddata = NULL;
  91.     struct targs *pta= (struct targs*)pdata;
  92.     if ( pdata == NULL )
  93.         goto EXIT_POINT;    
  94.     int connfd = pta->sockfd;
  95.     char buffer[1024];
  96.     printf("thread process socket:%d\n", connfd);
  97.     /*先收4个字节长度*/
  98.     bzero(buffer,sizeof(buffer));
  99.     if ( read(connfd,buffer,4)<=0 ){
  100.         goto EXIT_POINT;
  101.     }
  102.     /*再收内容*/
  103.     int len = atoi(buffer);
  104.     printf("packet length:%04d\n", len );
  105.     if ( len <= 0 ) goto EXIT_POINT;
  106.     preaddata = (char *)calloc(len+1, 1);
  107.     if ( !preaddata ) goto EXIT_POINT;
  108.     if ( read(connfd,preaddata ,len)<=0 ) {
  109.         printf("connetc closed.\r\n");
  110.         goto EXIT_POINT;
  111.     }
  112.     else
  113.     {
  114.         printf("recv from client:[%s]\r\n",preaddata );
  115.     }
  116. #if 1 // 以下这段代码可以替换成自己的实际业务代码,比如查询数据库等。
  117.     /*将小写转换成大写*/
  118.     int i = 0;
  119.     while ( i<len ){
  120.         char c = *(preaddata+i);
  121.         if ( c>='a' && c<='z' )
  122.             *(preaddata+i) -= ('a'-'A');
  123.         i++;
  124.     }
  125.     //模拟2秒等待时间
  126.     sleep(2);
  127. #endif
  128.     write(connfd, preaddata, len );
  129.     printf("return client:[%s]\r\n",preaddata);
  130.  
  131. EXIT_POINT:
  132.     if ( pta ){
  133.         close(pta->sockfd);
  134.         free(pta);
  135.     }
  136.     if (preaddata) free(preaddata);

  137.     /*释放thread,不然内存资源一直会占用不释放,造成泄漏。避免方法
  138.      可以在主线程pthread_join 回收,也可以通过detach分离释放*/
        pthread_detach(pthread_self());

  139.     return NULL;
  140. }
  141. void handle_sigcld(int signo)
  142. {
  143.     int pid,status;
  144.     pid = waitpid( -1, &status, 0);//-1表示等待任何子进程
  145.     //printf("child process %d exit with %d\n",pid,status);
  146. }

阅读(1820) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~