zoukankan      html  css  js  c++  java
  • 使用select+非阻塞socket写的网络数据转发程序 « Xiaoxia[PG]

    使用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. }  
  • 相关阅读:
    学习windows的半天+学习Git分布式系统的半天
    输出从1加到100的结果、打印100以内的质数、计算一个文件中的每个英文单词出现的次数
    Linux操作系统--初级--进程管理的命令
    Linux操作系统--初级--防火墙
    Linux操作系统--初级--dns服务
    Linux操作系统--初级--网络安全基础
    Linux操作系统--初级--进程管理
    Linux操作系统--初级--Linux网络
    Linux操作系统--初级--Linux磁盘管理
    Linux操作系统--初级--Linux的用户与用户组(权限管理)
  • 原文地址:https://www.cnblogs.com/lexus/p/2379137.html
Copyright © 2011-2022 走看看