亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫(kù)
最近訪問(wèn)板塊 發(fā)新帖
查看: 3573 | 回復(fù): 4
打印 上一主題 下一主題

[Linux] 關(guān)于select單線程實(shí)現(xiàn)并發(fā)問(wèn)題 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2014-09-04 19:42 |只看該作者 |倒序?yàn)g覽
本帖最后由 wander__漫游世界 于 2014-09-04 19:43 編輯

學(xué)習(xí)select實(shí)現(xiàn)單線程實(shí)現(xiàn)并發(fā),在網(wǎng)上找到兩種版本。
一種能夠?qū)崿F(xiàn)并發(fā)通信,一種只有一個(gè)客戶段能夠通信,十分不解。下面上源碼,求幫忙分析一下。
第一種能實(shí)現(xiàn)并發(fā):
  1. /*
  2.         Thu Sep 4,4:12PM,2014
  3.         @wander
  4.         email:czpwander@gmail.com       
  5.         process: select socket server
  6.         ps:?jiǎn)芜M(jìn)程用select實(shí)現(xiàn)并發(fā)socket
  7.         網(wǎng)上有幾種不同的實(shí)現(xiàn)方式,本程序是通過(guò)主進(jìn)程實(shí)現(xiàn)監(jiān)聽socket,然后用select實(shí)現(xiàn)連接socket
  8.         select 程序中是每次有一個(gè)新連接,然后將連接描述符添加到select描述符中,也就是一個(gè)一個(gè)添加。
  9. * */

  10. #include <stdio.h>
  11. #include <sys/socket.h>
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #include <netinet/in.h>
  15. #include <unistd.h>
  16. #include <stdlib.h>
  17. #include <sys/select.h>
  18. #include <sys/time.h>

  19. #define LEN 1024
  20. #define PORT 60606
  21. #define BACKLOG 2

  22. struct client{
  23.         int fd;               
  24.         struct sockaddr_in cli;
  25. };

  26. int main(void)
  27. {
  28.         struct client cl[FD_SETSIZE];//客戶端數(shù)組
  29.         int connfd;
  30.         int i;
  31.         int maxfd,sockfd;
  32.         int maxi = -1;
  33.         int nready;
  34.         char buf[LEN];// 接收發(fā)送socket buf
  35.         int listenfd = socket(AF_INET,SOCK_STREAM,0);//創(chuàng)建監(jiān)聽socket
  36.         if(listenfd < 0){
  37.                 perror("socket error\n");       
  38.                 exit(-1);
  39.         }

  40.         int opt = SO_REUSEADDR;
  41.         setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int));//設(shè)置解綁地址
  42.         struct sockaddr_in ser;
  43.         socklen_t ser_len = sizeof(ser);
  44.         ser.sin_family = AF_INET;
  45.         ser.sin_port = htons(PORT);
  46.         ser.sin_addr.s_addr = htonl(INADDR_ANY);
  47.        
  48.         int ret = bind(listenfd,(struct sockaddr*)&ser,ser_len);//bind
  49.         if(ret < 0){
  50.                 perror("bind error\n");
  51.                 exit(-1);
  52.         }
  53.        
  54.         ret = listen(listenfd,BACKLOG); //listen
  55.         if(ret < 0){
  56.                 perror("listen error\n");       
  57.                 exit(-1);
  58.         }
  59.        
  60.         //select
  61.         maxfd = listenfd;
  62.         for(i = 0;i < FD_SETSIZE;i ++){
  63.                 cl[i].fd = -1;
  64.         }
  65.         fd_set read_fds;
  66.         fd_set r_fds;
  67.         FD_ZERO(&read_fds);
  68.         FD_ZERO(&r_fds);
  69.         FD_SET(listenfd,&read_fds);

  70.         while(1){
  71.                 memset(buf,0,LEN);       
  72.                 struct sockaddr_in addr;
  73.                 r_fds = read_fds;//將select描述符集,賦值給r_fds
  74.                 socklen_t addr_len = sizeof(addr);
  75.                 bzero(&addr,addr_len);

  76.                 nready = select(maxfd+1,&r_fds,NULL,NULL,NULL);//  select
  77.                 if(ret < 0){
  78.                         perror("select error\n");
  79.                         exit(-1);
  80.                 }
  81.                 if(FD_ISSET(listenfd,&r_fds)){// 判斷是否有監(jiān)聽socket
  82.                         printf("get new connect\n");
  83.                         connfd = accept(listenfd,(struct sockaddr *)&addr,&addr_len);// accept socket
  84.                         if(connfd < 0){
  85.                                 perror("accept error\n");
  86.                                 exit(-1);
  87.                         }
  88.                         printf("accept ok\n");       
  89.                        
  90.                         //將得到客戶端地址 連接socketfd
  91.                         for(i = 0;i < FD_SETSIZE;i ++){
  92.                                 if(cl[i].fd < 0){
  93.                                         cl[i].fd = connfd;
  94.                                         cl[i].cli = addr;
  95.                                         printf("got connect from %s\n",inet_ntoa(cl[i].cli.sin_addr));
  96.                                         //printf("got connect from client %d\n",i);
  97.                                         break;
  98.                                 }
  99.                         }
  100.                         if(i == FD_SETSIZE){// 連接達(dá)到最大值
  101.                                 printf("too many client connect\n");       
  102.                                 continue;
  103.                         }
  104.                         FD_SET(connfd,&read_fds);//將連接sockefd添加到select描述符集中
  105.                         if(connfd > maxfd)// 判斷最大
  106.                                 maxfd = connfd;
  107.                         if(i > maxi){// 判斷最大連接數(shù)
  108.                                 maxi = i;
  109.                                 printf("maxi:%d\n",maxi);
  110.                         }
  111.                         if(--nready <= 0)
  112.                                 continue;//如果沒有連接,就繼續(xù)循環(huán)
  113.                 }

  114.                 for(i = 0;i <= maxi;i ++){// 判斷是否有數(shù)據(jù)發(fā)送
  115.                         if((sockfd = cl[i].fd) < 0)        //如果小于0,表示沒有客戶端連接
  116.                                 continue;
  117.                         if(FD_ISSET(sockfd,&r_fds)){
  118.                                 printf("get the data\n");
  119.                                 int r_size = recv(sockfd,buf,LEN,0);//接收數(shù)據(jù)
  120.                                 if(r_size == 0){
  121.                                         close(sockfd);
  122.                                         printf("close the %d client\n",i);
  123.                                 }
  124.                                 else if(r_size > 0){
  125.                                         printf("the client %d:",i);
  126.                                         printf("%s \n",buf);
  127.                                 }
  128.                                 if(--nready <= 0)
  129.                                         break;
  130.                         }
  131.                 }
  132.         }
  133.        
  134.         close(connfd);
  135.         close(listenfd);
  136. }



















復(fù)制代碼
第二種,網(wǎng)上很多是第二種,但是能夠建立連接,但是不能實(shí)現(xiàn)并發(fā)通信
  1. /* 實(shí)現(xiàn)功能:通過(guò)select處理多個(gè)socket
  2. * 監(jiān)聽一個(gè)端口,監(jiān)聽到有鏈接時(shí),添加到select的w.
  3. */
  4. //#include "select.h"
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <sys/socket.h>
  8. #include <sys/select.h>
  9. #include <sys/time.h>
  10. #include <netinet/in.h>
  11. #include <string.h>

  12. typedef struct _CLIENT{
  13.     int fd;
  14.     struct sockaddr_in addr; /* client's address information */
  15. } CLIENT;

  16. #define MYPORT 60606

  17. //最多處理的connect
  18. #define BACKLOG 2

  19. //最多處理的connect
  20. CLIENT client[BACKLOG];

  21. //當(dāng)前的連接數(shù)
  22. int currentClient = 0;

  23. //數(shù)據(jù)接受 buf
  24. #define REVLEN 10
  25. char recvBuf[REVLEN];
  26. //顯示當(dāng)前的connection
  27. void showClient();

  28. int main()
  29. {
  30.     int i, ret, sinSize;
  31.     int recvLen = 0;
  32.     fd_set readfds, writefds;
  33.     int sockListen, sockSvr, sockMax;
  34.     struct timeval timeout;
  35.     struct sockaddr_in server_addr;
  36.     struct sockaddr_in client_addr;

  37.         //將客戶端端描述符置1
  38.     for(i=0; i<BACKLOG; i++)
  39.     {
  40.         client[i].fd = -1;
  41.     }

  42.     //socket
  43.     if((sockListen=socket(AF_INET, SOCK_STREAM, 0)) < 0)
  44.     {
  45.         printf("socket error\n");
  46.         return -1;
  47.     }

  48.         int opt = SO_REUSEADDR;
  49.         setsockopt(sockListen,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int));
  50.     bzero(&server_addr, sizeof(server_addr));
  51.     server_addr.sin_family  =  AF_INET;
  52.     server_addr.sin_port = htons(MYPORT);
  53.     server_addr.sin_addr.s_addr  =  htonl(INADDR_ANY);

  54.     //bind
  55.     if(bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
  56.     {
  57.         printf("bind error\n");
  58.         return -1;
  59.     }

  60.     //listen
  61.     if(listen(sockListen, 5) < 0)
  62.     {
  63.         printf("listen error\n");
  64.         return -1;
  65.     }

  66.     for(i=0; i<BACKLOG; i++)
  67.     {
  68.         client[i].fd = -1;
  69.     }

  70.     //select
  71.     while(1)
  72.     {
  73.         FD_ZERO(&readfds);
  74.         FD_SET(sockListen, &readfds);
  75.         sockMax = sockListen;
  76.    
  77.         //加入client
  78.         for(i=0; i<BACKLOG; i++)
  79.         {
  80.             if(client[i].fd >0)
  81.             {
  82.                 FD_SET(client[i].fd, &readfds);
  83.                 if(sockMax<client[i].fd)
  84.                     sockMax = client[i].fd;
  85.             }
  86.         }
  87.         
  88.         timeout.tv_sec=10;               
  89.         timeout.tv_usec=0;
  90.         //select
  91.         ret = select((int)sockMax+1, &readfds, NULL, NULL, &timeout);
  92.         if(ret < 0)
  93.         {
  94.             printf("select error\n");
  95.             break;
  96.         }
  97.         else if(ret == 0)
  98.         {
  99.             printf("timeout ...\n");
  100.             continue;
  101.         }
  102.         //printf("test111\n");
  103.    
  104.         //讀取數(shù)據(jù)
  105.         for(i=0; i<BACKLOG; i++)
  106.         {
  107.             if(client[i].fd>0 && FD_ISSET(client[i].fd, &readfds))
  108.             {
  109.                 if(recvLen != REVLEN)
  110.                 {
  111.                     while(1)
  112.                     {
  113.                         //recv數(shù)據(jù)
  114.                         ret = recv(client[i].fd, (char *)recvBuf+recvLen, REVLEN-recvLen, 0);
  115.                         if(ret == 0)
  116.                         {
  117.                             client[i].fd = -1;
  118.                             recvLen = 0;
  119.                             break;
  120.                         }
  121.                         else if(ret < 0)
  122.                         {
  123.                             client[i].fd = -1;
  124.                             recvLen = 0;
  125.                             break;
  126.                         }
  127.                         //數(shù)據(jù)接受正常
  128.                         recvLen = recvLen+ret;
  129.                         if(recvLen<REVLEN)
  130.                         {
  131.                             continue;
  132.                         }
  133.                         else
  134.                         {
  135.                             //數(shù)據(jù)接受完畢
  136.                             printf("%s, buf = %s\n", inet_ntoa(client[i].addr.sin_addr) , recvBuf);
  137.                             //close(client[i].fd);
  138.                             //client[i].fd = -1;
  139.                             recvLen = 0;
  140.                             break;
  141.                         }
  142.                     }
  143.                 }
  144.             }
  145.         }
  146.    
  147.         //如果可讀
  148.         if(FD_ISSET(sockListen, &readfds))
  149.         {
  150.             printf("isset\n");
  151.             sockSvr = accept(sockListen, NULL, NULL);//(struct sockaddr*)&client_addr
  152.         
  153.             if(sockSvr == -1)
  154.             {
  155.                 printf("accpet error\n");
  156.             }
  157.             else
  158.             {
  159.                 currentClient++;
  160.             }
  161.         
  162.             for(i=0; i<BACKLOG; i++)
  163.             {
  164.                 if(client[i].fd < 0)
  165.                 {
  166.                     client[i].fd = sockSvr;
  167.                     client[i].addr = client_addr;
  168.                     printf("You got a connection from %s \n",inet_ntoa(client[i].addr.sin_addr) );
  169.                     break;
  170.                 }
  171.             }
  172.             //close(sockListen);
  173.         }
  174.     }

  175.     printf("test\n");
  176.     return 0;
  177. }

  178. //顯示當(dāng)前的connection
  179. void showClient()
  180. {
  181.     int i;
  182.     printf("client count = %d\n", currentClient);

  183.     for(i=0; i<BACKLOG; i++)
  184.     {
  185.         printf("[%d] = %d", i, client[i].fd);
  186.     }
  187.     printf("\n");
  188. }
復(fù)制代碼

論壇徽章:
0
2 [報(bào)告]
發(fā)表于 2014-09-05 09:23 |只看該作者
不想貼子沉了。頂一下。還是希望大神們能夠看看,相互交流一下。
樓主不想只是將代碼敲一遍,然后就沒有了。樓主想深入進(jìn)去好好學(xué)習(xí),期望擺脫菜鳥,以后也能為linux社區(qū)做貢獻(xiàn)

論壇徽章:
0
3 [報(bào)告]
發(fā)表于 2014-09-10 21:36 |只看該作者
沒人知道,天啊,竟然沒人知道

論壇徽章:
0
4 [報(bào)告]
發(fā)表于 2014-11-17 10:23 |只看該作者
回復(fù) 3# wander__漫游世界


    樓主研究的怎么樣了,我也在學(xué)習(xí)select呢,你說(shuō)的第一個(gè)例子的源碼就是<<unix網(wǎng)絡(luò)編程>>上的代碼吧,第二個(gè)例子的源碼我也不明白,我也想知道為什么,樓主有答案了么?
   樓主給解釋下吧

論壇徽章:
15
射手座
日期:2014-11-29 19:22:4915-16賽季CBA聯(lián)賽之青島
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16賽季CBA聯(lián)賽之四川
日期:2017-02-07 21:08:572015年亞冠紀(jì)念徽章
日期:2015-11-06 12:31:58每日論壇發(fā)貼之星
日期:2015-08-04 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2015-08-04 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2015-07-12 22:20:002015亞冠之浦和紅鉆
日期:2015-07-08 10:10:132015亞冠之大阪鋼巴
日期:2015-06-29 11:21:122015亞冠之廣州恒大
日期:2015-05-22 21:55:412015年亞洲杯之伊朗
日期:2015-04-10 16:28:25
5 [報(bào)告]
發(fā)表于 2014-11-30 09:54 |只看該作者
wander__漫游世界 發(fā)表于 2014-09-10 21:36
沒人知道,天啊,竟然沒人知道

第二個(gè),為什么每次readfd都要accept呢?不是每個(gè)fd都要accept的。
您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國(guó)互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過(guò)ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP