浙江省高等学校教师教育理论培训

微信搜索“毛凌志岗前心得”小程序

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

使用select+非阻塞socket写的网络数据转发程序 « Xiaoxia[PG]

 从实践之中,我又学到东西了!使用select的时候,无论是使用非阻塞还是阻塞socket,调用recv和send函数返回0都意味着socket被远程关闭!!!

    select+阻塞socket版本请见  http://xiaoxia.org/2675.html

 

    对比两个版本,从理论上可以知道select+非阻塞socket要高效得多。在与远程服务器connect的时候,程序要等待连接完全建立完毕才返回,这里会让程序产生延迟。而在非阻塞中不会等待,直接去处理其它连接。所以,我打算在fox3(http://code.google.com/p/icefox)的开发中使用select+非阻塞socket。至于为何不使用epoll或者iocp是因为我考虑了可移植性。

 

   下面是代码,看球赛去!

 

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <sys/socket.h>  
  4. #include <arpa/inet.h>  
  5. #include <netdb.h>  
  6. #include <errno.h>  
  7. #include <fcntl.h>  
  8.   
  9. #define closesocket close  
  10. #define client_count 100  
  11. #define BUFFER_SIZE 8192  
  12.   
  13. struct connection{  
  14.     int clientfd;  
  15.     int remotefd;  
  16.     char clientbuf[BUFFER_SIZE];  
  17.     char remotebuf[BUFFER_SIZE];  
  18.     int clientbuf_size;  
  19.     int remotebuf_size;  
  20. } conns[client_count] = {0};  
  21.   
  22. static void remove_client(int i)  
  23. {  
  24.     shutdown(conns[i].clientfd, SHUT_RD);  
  25.     closesocket(conns[i].clientfd);  
  26.     shutdown(conns[i].remotefd, SHUT_RD);  
  27.     closesocket(conns[i].remotefd);  
  28.     conns[i].clientfd =  
  29.     conns[i].remotefd = 0;  
  30. }  
  31.   
  32. static int get_client()  
  33. {  
  34.     int i;  
  35.     for( i = 0; i<client_count; i++)  
  36.         if(!conns[i].clientfd)  
  37.             return i;  
  38.     return 0;  
  39. }  
  40.   
  41. static int set_nonblocking(int sock)  
  42. {  
  43.     int opts;  
  44.     opts = fcntl(sock, F_GETFL);  
  45.     if(opts < 0)  
  46.         return -1;  
  47.     opts = opts | O_NONBLOCK;  
  48.     if(fcntl(sock, F_SETFL, opts) < 0)  
  49.         return(-1);  
  50.     return 0;  
  51. }  
  52.   
  53. int main(int argc, char **argv)  
  54. {  
  55.     fd_set fdreads, fdwrites;  
  56.     const int buf_size = 1024*32;  
  57.     int ret;  
  58.     char buf[buf_size];  
  59.     int sock = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );  
  60.     ret = 1;  
  61.     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&ret, sizeof(ret)); //端口复用  
  62.     struct sockaddr_in addr = {0};  
  63.     struct sockaddr_in remote_addr = {0};  
  64.     addr.sin_family = remote_addr.sin_family = PF_INET;  
  65.     addr.sin_addr.s_addr = INADDR_ANY;  
  66.     addr.sin_port = htons( 1080 );  
  67.     remote_addr.sin_addr.s_addr = inet_addr("221.130.162.247");  
  68.     remote_addr.sin_port = htons( 80 );  
  69.     if( bind( sock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in) ) < 0 )  
  70.         perror("failed to bind socket");  
  71.     listen( sock , 5);  
  72.     printf("listening\n");  
  73.     for(;;){  
  74.         int i, j, k, lastfd=0;  
  75.         FD_ZERO(&fdreads);  
  76.         FD_ZERO(&fdwrites);  
  77.         FD_SET( sock, &fdreads);  
  78.         for( i=0; i<client_count; i++)  
  79.             if(conns[i].clientfd){  
  80.                 if( conns[i].clientbuf_size == 0 ){  
  81.                     FD_SET( conns[i].clientfd, &fdreads );  
  82.                 }else{  
  83.                     FD_SET( conns[i].remotefd, &fdwrites );  
  84.                 }  
  85.                 if( conns[i].remotebuf_size == 0){  
  86.                     FD_SET( conns[i].remotefd, &fdreads );  
  87.                 }else{  
  88.                     FD_SET( conns[i].clientfd, &fdwrites );  
  89.                 }  
  90.             }  
  91.         ret = select(client_count*2+2, &fdreads, &fdwrites, 0, 0);  
  92.         switch(ret){  
  93.         case -1:  
  94.             perror("error");  
  95.             break;  
  96.         case 0:  
  97.             perror("timeout?");  
  98.             break;  
  99.         default:  
  100.             if(FD_ISSET(sock, &fdreads)){  
  101.                 int j = get_client();  
  102.                 printf("accept %d\n", j);  
  103.                 int len = sizeof(struct sockaddr_in);  
  104.                 conns[j].clientfd = accept(sock, 0, 0);  
  105.                 conns[j].remotefd = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );  
  106.                 addr.sin_port = htons( 0 );  
  107.                 set_nonblocking(conns[j].clientfd);  
  108.                 set_nonblocking(conns[j].remotefd);  
  109.                 bind( conns[j].remotefd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in) );  
  110.                 connect( conns[j].remotefd, (struct sockaddr*)&remote_addr, sizeof(struct sockaddr_in) );  
  111.             }  
  112.             for( j=0; j<client_count; j++){  
  113.                 if(!conns[j].clientfd) continue;  
  114.                 if(FD_ISSET(conns[j].clientfd, &fdreads) ){  
  115.                     int ret = recv(conns[j].clientfd, conns[j].clientbuf, BUFFER_SIZE, 0);  
  116.                     if( ret > 0 )  
  117.                         conns[j].clientbuf_size = ret;  
  118.                     if( ret <= 0 )  
  119.                         remove_client(j);  
  120.                 }  
  121.                 if(FD_ISSET(conns[j].remotefd, &fdreads) ){  
  122.                     int ret = recv(conns[j].remotefd, conns[j].remotebuf, BUFFER_SIZE, 0);  
  123.                     if( ret > 0 )  
  124.                         conns[j].remotebuf_size = ret;  
  125.                     if( ret <= 0 )  
  126.                         remove_client(j);  
  127.                 }  
  128.                 if(FD_ISSET(conns[j].clientfd, &fdwrites) ){  
  129.                     int ret = send(conns[j].clientfd, conns[j].remotebuf, conns[j].remotebuf_size, 0);  
  130.                     if( ret > 0 )  
  131.                         conns[j].remotebuf_size -= ret;  
  132.                     if( ret <= 0 )  
  133.                         remove_client(j);  
  134.                 }  
  135.                 if(FD_ISSET(conns[j].remotefd, &fdwrites) ){  
  136.                     int ret = send(conns[j].remotefd, conns[j].clientbuf, conns[j].clientbuf_size, 0);  
  137.                     if( ret > 0 )  
  138.                         conns[j].clientbuf_size -= ret;  
  139.                     if( ret <= 0 )  
  140.                         remove_client(j);  
  141.                 }  
  142.             }  
  143.         }  
  144.     }  
  145.     return 0;  
  146. }  
posted on 2012-03-04 12:05  lexus  阅读(463)  评论(0)    收藏  举报