zoukankan      html  css  js  c++  java
  • 8.1 服务器开发 API 函数封装,select 优化服务器和客户端

      1 #include <unistd.h>
      2 #include <sys/types.h>
      3 #include <sys/socket.h>
      4 #include <netinet/in.h>
      5 #include <arpa/inet.h>
      6 #include <signal.h>
      7 #include <sys/wait.h>
      8 
      9 #include <fcntl.h>
     10 
     11 
     12 #include <stdlib.h>
     13 #include <stdio.h>
     14 #include <errno.h>
     15 #include <string.h>
     16 
     17 #include "commsocket.h"
     18 
     19 typedef struct _SckHandle
     20 {
     21     int sockArray[100];
     22     int arrayNum;
     23     int sockfd;
     24     int contime;
     25     int sendtime;
     26     int revtime;
     27 
     28 }SckHandle;
     29 
     30 /**
     31  * readn - 读取固定字节数
     32  * @fd: 文件描述符
     33  * @buf: 接收缓冲区
     34  * @count: 要读取的字节数
     35  * 成功返回count,失败返回-1,读到EOF返回<count
     36  */
     37 ssize_t readn(int fd, void *buf, size_t count)
     38 {
     39     size_t nleft = count;
     40     ssize_t nread;
     41     char *bufp = (char*)buf;
     42 
     43     while (nleft > 0)
     44     {
     45         if ((nread = read(fd, bufp, nleft)) < 0)
     46         {
     47             if (errno == EINTR)
     48                 continue;
     49             return -1;
     50         }
     51         else if (nread == 0)
     52             return count - nleft;
     53 
     54         bufp += nread;
     55         nleft -= nread;
     56     }
     57 
     58     return count;
     59 }
     60 
     61 /**
     62  * writen - 发送固定字节数
     63  * @fd: 文件描述符
     64  * @buf: 发送缓冲区
     65  * @count: 要读取的字节数
     66  * 成功返回count,失败返回-1
     67  */
     68 ssize_t writen(int fd, const void *buf, size_t count)
     69 {
     70     size_t nleft = count;
     71     ssize_t nwritten;
     72     char *bufp = (char*)buf;
     73 
     74     while (nleft > 0)
     75     {
     76         if ((nwritten = write(fd, bufp, nleft)) < 0)
     77         {
     78             if (errno == EINTR)
     79                 continue;
     80             return -1;
     81         }
     82         else if (nwritten == 0)
     83             continue;
     84 
     85         bufp += nwritten;
     86         nleft -= nwritten;
     87     }
     88 
     89     return count;
     90 }
     91 
     92 /**
     93  * recv_peek - 仅仅查看套接字缓冲区数据,但不移除数据
     94  * @sockfd: 套接字
     95  * @buf: 接收缓冲区
     96  * @len: 长度
     97  * 成功返回>=0,失败返回-1
     98  */
     99 ssize_t recv_peek(int sockfd, void *buf, size_t len)
    100 {
    101     while (1)
    102     {
    103         int ret = recv(sockfd, buf, len, MSG_PEEK);
    104         if (ret == -1 && errno == EINTR)
    105             continue;
    106         return ret;
    107     }
    108 }
    109 
    110 
    111 //函数声明
    112 //客户端环境初始化
    113 int sckCliet_init(void **handle, int contime, int sendtime, int revtime, int nConNum)
    114 {
    115     int     ret = 0;
    116     if (handle == NULL ||contime<0 || sendtime<0 || revtime<0)
    117     {
    118         ret = Sck_ErrParam;
    119         printf("func sckCliet_init() err: %d, check  (handle == NULL ||contime<0 || sendtime<0 || revtime<0)
    ", ret);
    120         return ret;
    121     }
    122     
    123     SckHandle *tmp = (SckHandle *)malloc(sizeof(SckHandle));
    124     if (tmp == NULL)
    125     {
    126         ret = Sck_ErrMalloc;
    127         printf("func sckCliet_init() err: malloc %d
    ", ret);
    128         return ret;
    129     }
    130     
    131     tmp->contime = contime;
    132     tmp->sendtime = sendtime;
    133     tmp->revtime = revtime;
    134     tmp->arrayNum = nConNum;
    135         
    136         
    137     /*
    138     int sockfd;
    139     int i = 0;
    140     for (i=0; i<1; i++)
    141     {
    142         //链表的顺序
    143         sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    144         if (sockfd < 0)
    145         {
    146             ret = errno;
    147             printf("func socket() err:  %d
    ", ret);
    148             return ret;
    149         }
    150         tmp->sockfd = sockfd;
    151     }
    152     */
    153 
    154     *handle = tmp; 
    155     return ret;
    156 }
    157 
    158 /**
    159  * activate_noblock - 设置I/O为非阻塞模式
    160  * @fd: 文件描符符
    161  */
    162 int activate_nonblock(int fd)
    163 {
    164     int ret = 0;
    165     int flags = fcntl(fd, F_GETFL);
    166     if (flags == -1)
    167     {
    168         ret = flags;
    169         printf("func activate_nonblock() err:%d", ret);
    170         return ret;
    171     }
    172         
    173 
    174     flags |= O_NONBLOCK;
    175     ret = fcntl(fd, F_SETFL, flags);
    176     if (ret == -1)
    177     {
    178         printf("func activate_nonblock() err:%d", ret);
    179         return ret;
    180     }
    181     return ret;
    182 }
    183 
    184 /**
    185  * deactivate_nonblock - 设置I/O为阻塞模式
    186  * @fd: 文件描符符
    187  */
    188 int deactivate_nonblock(int fd)
    189 {
    190     int ret = 0;
    191     int flags = fcntl(fd, F_GETFL);
    192     if (flags == -1)
    193     {
    194         ret = flags;
    195         printf("func deactivate_nonblock() err:%d", ret);
    196         return ret;
    197     }
    198 
    199     flags &= ~O_NONBLOCK;
    200     ret = fcntl(fd, F_SETFL, flags);
    201     if (ret == -1)
    202     {
    203         printf("func deactivate_nonblock() err:%d", ret);
    204         return ret;
    205     }
    206     return ret;
    207 }
    208 
    209 
    210 
    211 /**
    212  * connect_timeout - connect
    213  * @fd: 套接字
    214  * @addr: 要连接的对方地址
    215  * @wait_seconds: 等待超时秒数,如果为0表示正常模式
    216  * 成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT
    217  */
    218 static int connect_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds)
    219 {
    220     int ret;
    221     socklen_t addrlen = sizeof(struct sockaddr_in);
    222 
    223     if (wait_seconds > 0)
    224         activate_nonblock(fd);
    225 
    226     ret = connect(fd, (struct sockaddr*)addr, addrlen);
    227     if (ret < 0 && errno == EINPROGRESS)
    228     {
    229         //printf("11111111111111111111
    ");
    230         fd_set connect_fdset;
    231         struct timeval timeout;
    232         FD_ZERO(&connect_fdset);
    233         FD_SET(fd, &connect_fdset);
    234         timeout.tv_sec = wait_seconds;
    235         timeout.tv_usec = 0;
    236         do
    237         {
    238             // 一但连接建立,则套接字就可写  所以connect_fdset放在了写集合中
    239             ret = select(fd + 1, NULL, &connect_fdset, NULL, &timeout);
    240         } while (ret < 0 && errno == EINTR);
    241         if (ret == 0)
    242         {
    243             ret = -1;
    244             errno = ETIMEDOUT;
    245         }
    246         else if (ret < 0)
    247             return -1;
    248         else if (ret == 1)
    249         {
    250             //printf("22222222222222222
    ");
    251             /* ret返回为1(表示套接字可写),可能有两种情况,一种是连接建立成功,一种是套接字产生错误,*/
    252             /* 此时错误信息不会保存至errno变量中,因此,需要调用getsockopt来获取。 */
    253             int err;
    254             socklen_t socklen = sizeof(err);
    255             int sockoptret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &socklen);
    256             if (sockoptret == -1)
    257             {
    258                 return -1;
    259             }
    260             if (err == 0)
    261             {
    262                 //printf("3333333333333
    ");
    263                 ret = 0;
    264             }
    265             else
    266             {
    267                 //printf("4444444444444444:%d
    ", err);
    268                 errno = err;
    269                 ret = -1;
    270             }
    271         }
    272     }
    273     if (wait_seconds > 0)
    274     {
    275         deactivate_nonblock(fd);
    276     }
    277     return ret;
    278 }
    279 
    280 
    281 
    282 //
    283 int sckCliet_getconn(void *handle, char *ip, int port, int *connfd)
    284 {
    285     
    286     int ret = 0;
    287     SckHandle  *tmp = NULL;
    288     if (handle == NULL || ip==NULL || connfd==NULL || port<0 || port>65537)
    289     {
    290         ret = Sck_ErrParam;
    291         printf("func sckCliet_getconn() err: %d, check  (handle == NULL || ip==NULL || connfd==NULL || port<0 || port>65537) 
    ", ret);
    292         return ret;
    293     }
    294     
    295     //
    296     int sockfd;
    297     sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    298     if (sockfd < 0)
    299     {
    300         ret = errno;
    301         printf("func socket() err:  %d
    ", ret);
    302         return ret;
    303     }
    304     
    305     struct sockaddr_in servaddr;
    306     memset(&servaddr, 0, sizeof(servaddr));
    307     servaddr.sin_family = AF_INET;
    308     servaddr.sin_port = htons(port);
    309     servaddr.sin_addr.s_addr = inet_addr(ip);
    310     
    311     tmp = (SckHandle* )handle;
    312 
    313     /*
    314     ret = connect(sockfd, (struct sockaddr*) (&servaddr), sizeof(servaddr));
    315     if (ret < 0)
    316     {
    317         ret = errno;
    318         printf("func connect() err:  %d
    ", ret);
    319         return ret;
    320     }
    321     */
    322     
    323     ret = connect_timeout(sockfd, (struct sockaddr_in*) (&servaddr), (unsigned int )tmp->contime);
    324     if (ret < 0)
    325     {
    326         if (ret==-1 && errno == ETIMEDOUT)
    327         {
    328             ret = Sck_ErrTimeOut;
    329             return ret;
    330         }
    331         else
    332         {
    333             printf("func connect_timeout() err:  %d
    ", ret);
    334         }
    335     }
    336     
    337     *connfd = sockfd;
    338    
    339        return ret;
    340     
    341 }
    342 
    343 
    344 
    345 /**
    346  * write_timeout - 写超时检测函数,不含写操作
    347  * @fd: 文件描述符
    348  * @wait_seconds: 等待超时秒数,如果为0表示不检测超时
    349  * 成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT
    350  */
    351 int write_timeout(int fd, unsigned int wait_seconds)
    352 {
    353     int ret = 0;
    354     if (wait_seconds > 0)
    355     {
    356         fd_set write_fdset;
    357         struct timeval timeout;
    358 
    359         FD_ZERO(&write_fdset);
    360         FD_SET(fd, &write_fdset);
    361 
    362         timeout.tv_sec = wait_seconds;
    363         timeout.tv_usec = 0;
    364         do
    365         {
    366             ret = select(fd + 1, NULL, &write_fdset, NULL, &timeout);
    367         } while (ret < 0 && errno == EINTR);
    368 
    369         if (ret == 0)
    370         {
    371             ret = -1;
    372             errno = ETIMEDOUT;
    373         }
    374         else if (ret == 1)
    375             ret = 0;
    376     }
    377 
    378     return ret;
    379 }
    380 
    381 
    382 //客户端发送报文
    383 int sckClient_send(void *handle, int  connfd,  unsigned char *data, int datalen)
    384 {
    385     int     ret = 0;
    386     
    387     SckHandle  *tmp = NULL;
    388     tmp = (SckHandle *)handle;
    389     ret = write_timeout(connfd, tmp->sendtime);
    390     if (ret == 0)
    391     {
    392         int writed = 0;
    393         unsigned char *netdata = ( unsigned char *)malloc(datalen + 4);
    394         if ( netdata == NULL)
    395         {
    396             ret = Sck_ErrMalloc;
    397             printf("func sckClient_send() mlloc Err:%d
     ", ret);
    398             return ret;
    399         }
    400         int netlen = htonl(datalen);
    401         memcpy(netdata, &netlen, 4);
    402         memcpy(netdata+4, data, datalen);
    403         
    404         writed = writen(connfd, netdata, datalen + 4);
    405         if (writed < (datalen + 4) )
    406         {
    407             if (netdata != NULL) 
    408             {
    409                 free(netdata);
    410                 netdata = NULL;
    411             }
    412             return writed;
    413         }
    414           
    415     }
    416     
    417     if (ret < 0)
    418     {
    419         //失败返回-1,超时返回-1并且errno = ETIMEDOUT
    420         if (ret == -1 && errno == ETIMEDOUT)
    421         {
    422             ret = Sck_ErrTimeOut;
    423             printf("func sckClient_send() mlloc Err:%d
     ", ret);
    424             return ret;
    425         }
    426         return ret;
    427     }
    428     
    429     return ret;
    430 }
    431 
    432 
    433 
    434 /**
    435  * read_timeout - 读超时检测函数,不含读操作
    436  * @fd: 文件描述符
    437  * @wait_seconds: 等待超时秒数,如果为0表示不检测超时
    438  * 成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT
    439  */
    440 int read_timeout(int fd, unsigned int wait_seconds)
    441 {
    442     int ret = 0;
    443     if (wait_seconds > 0)
    444     {
    445         fd_set read_fdset;
    446         struct timeval timeout;
    447 
    448         FD_ZERO(&read_fdset);
    449         FD_SET(fd, &read_fdset);
    450 
    451         timeout.tv_sec = wait_seconds;
    452         timeout.tv_usec = 0;
    453         
    454         //select返回值三态
    455         //1 若timeout时间到(超时),没有检测到读事件 ret返回=0
    456         //2 若ret返回<0 &&  errno == EINTR 说明select的过程中被别的信号中断(可中断睡眠原理)
    457         //2-1 若返回-1,select出错
    458         //3 若ret返回值>0 表示有read事件发生,返回事件发生的个数
    459         
    460         do
    461         {
    462             ret = select(fd + 1, &read_fdset, NULL, NULL, &timeout);
    463         } while (ret < 0 && errno == EINTR); 
    464 
    465         if (ret == 0)
    466         {
    467             ret = -1;
    468             errno = ETIMEDOUT;
    469         }
    470         else if (ret == 1)
    471             ret = 0;
    472     }
    473 
    474     return ret;
    475 }
    476 
    477 //客户端端接受报文
    478 int sckClient_rev(void *handle,  int  connfd, unsigned char *out, int *outlen)
    479 {
    480     
    481     int        ret = 0;
    482     SckHandle *tmpHandle = (SckHandle *)handle;
    483     
    484     if (handle==NULL || out==NULL)
    485     {
    486         ret = Sck_ErrParam;
    487         printf("func sckClient_rev() timeout , err:%d 
    ", Sck_ErrTimeOut);
    488         return ret;
    489     }
    490     
    491     ret =  read_timeout(connfd, tmpHandle->revtime ); //bugs modify bombing
    492     if (ret != 0)
    493     {
    494         if (ret==-1 || errno == ETIMEDOUT)
    495         {
    496             ret = Sck_ErrTimeOut;
    497             printf("func sckClient_rev() timeout , err:%d 
    ", Sck_ErrTimeOut);
    498             return ret;
    499         }
    500         else
    501         {
    502             printf("func sckClient_rev() timeout , err:%d 
    ", Sck_ErrTimeOut);
    503             return ret;
    504         }    
    505     }
    506     
    507     int netdatalen = 0;
    508     ret = readn(connfd, &netdatalen,  4); //读包头 4个字节
    509     if (ret == -1)
    510     {
    511         printf("func readn() err:%d 
    ", ret);
    512         return ret;
    513     }
    514     else if (ret < 4)
    515     {
    516         ret = Sck_ErrPeerClosed;
    517         printf("func readn() err peer closed:%d 
    ", ret);
    518         return ret;
    519     }
    520     
    521     int n;
    522     n = ntohl(netdatalen);
    523     ret = readn(connfd, out, n); //根据长度读数据
    524     if (ret == -1)
    525     {
    526         printf("func readn() err:%d 
    ", ret);
    527         return ret;
    528     }
    529     else if (ret < n)
    530     {
    531         ret = Sck_ErrPeerClosed;
    532         printf("func readn() err peer closed:%d 
    ", ret);
    533         return ret;
    534     }
    535     
    536     *outlen = n;
    537     
    538     return 0;
    539 }
    540 
    541 // 客户端环境释放 
    542 int sckClient_destroy(void *handle)
    543 {
    544     if (handle != NULL)
    545     {
    546         free(handle);
    547     }
    548     return 0;
    549 }
    550 
    551 int sckCliet_closeconn(int connfd)
    552 {
    553     if (connfd >=0 )
    554     {
    555         close(connfd);
    556     }
    557     return 0;
    558 }
    559 
    560 
    561 
    562 /////////////////////////////////////////////////////////////////////////////////////
    563 //函数声明
    564 //服务器端初始化
    565 int sckServer_init(int port, int *listenfd)
    566 {
    567     int     ret = 0;
    568     int mylistenfd;
    569     struct sockaddr_in servaddr;
    570     memset(&servaddr, 0, sizeof(servaddr));
    571     servaddr.sin_family = AF_INET;
    572     servaddr.sin_port = htons(port);
    573     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    574     
    575         
    576     mylistenfd = socket(PF_INET, SOCK_STREAM, 0);
    577     if (mylistenfd < 0)
    578     {
    579         ret = errno ;
    580         printf("func socket() err:%d 
    ", ret);
    581         return ret;
    582     }
    583         
    584 
    585     int on = 1;
    586     ret = setsockopt(mylistenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );
    587     if (ret < 0)
    588     {
    589         ret = errno ;
    590         printf("func setsockopt() err:%d 
    ", ret);
    591         return ret;
    592     }
    593     
    594 
    595     ret = bind(mylistenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
    596     if (ret < 0)
    597     {
    598         ret = errno ;
    599         printf("func bind() err:%d 
    ", ret);
    600         return ret;
    601     }
    602         
    603     ret = listen(mylistenfd, SOMAXCONN);
    604     if (ret < 0)
    605     {
    606         ret = errno ;
    607         printf("func listen() err:%d 
    ", ret);
    608         return ret;
    609     }
    610         
    611     *listenfd = mylistenfd;
    612 
    613     return 0;
    614 }
    615 
    616 /**
    617  * accept_timeout - 带超时的accept
    618  * @fd: 套接字
    619  * @addr: 输出参数,返回对方地址
    620  * @wait_seconds: 等待超时秒数,如果为0表示正常模式
    621  * 成功(未超时)返回已连接套接字,超时返回-1并且errno = ETIMEDOUT
    622  */
    623 int accept_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds)
    624 {
    625     int ret;
    626     socklen_t addrlen = sizeof(struct sockaddr_in);
    627 
    628     if (wait_seconds > 0)
    629     {
    630         fd_set accept_fdset;
    631         struct timeval timeout;
    632         FD_ZERO(&accept_fdset);
    633         FD_SET(fd, &accept_fdset);
    634         timeout.tv_sec = wait_seconds;
    635         timeout.tv_usec = 0;
    636         do
    637         {
    638             ret = select(fd + 1, &accept_fdset, NULL, NULL, &timeout);
    639         } while (ret < 0 && errno == EINTR);
    640         if (ret == -1)
    641             return -1;
    642         else if (ret == 0)
    643         {
    644             errno = ETIMEDOUT;
    645             return -1;
    646         }
    647     }
    648 
    649     //一但检测出 有select事件发生,表示对等方完成了三次握手,客户端有新连接建立
    650     //此时再调用accept将不会堵塞
    651     if (addr != NULL)
    652         ret = accept(fd, (struct sockaddr*)addr, &addrlen); //返回已连接套接字
    653     else
    654         ret = accept(fd, NULL, NULL);
    655         if (ret == -1)
    656         {
    657             ret = errno;
    658             printf("func accept() err:%d 
    ", ret);
    659             return ret;
    660         }
    661     
    662 
    663     return ret;
    664 }
    665 
    666 int sckServer_accept(int listenfd, int *connfd,  int timeout)
    667 {
    668     int    ret = 0;
    669     
    670     ret = accept_timeout(listenfd, NULL, (unsigned int) timeout);
    671     if (ret < 0)
    672     {
    673         if (ret == -1 && errno == ETIMEDOUT)
    674         {
    675             ret = Sck_ErrTimeOut;
    676             printf("func accept_timeout() timeout err:%d 
    ", ret);
    677             return ret;
    678         }
    679         else
    680         {
    681             ret = errno;
    682             printf("func accept_timeout() err:%d 
    ", ret);
    683             return ret;
    684         }
    685     }
    686     
    687     *connfd = ret;
    688     return 0;
    689 }
    690 //服务器端发送报文
    691 int sckServer_send(int connfd,  unsigned char *data, int datalen, int timeout)
    692 {
    693     int     ret = 0;
    694     
    695     ret = write_timeout(connfd, timeout);
    696     if (ret == 0)
    697     {
    698         int writed = 0;
    699         unsigned char *netdata = ( unsigned char *)malloc(datalen + 4);
    700         if ( netdata == NULL)
    701         {
    702             ret = Sck_ErrMalloc;
    703             printf("func sckServer_send() mlloc Err:%d
     ", ret);
    704             return ret;
    705         }
    706         int netlen = htonl(datalen);
    707         memcpy(netdata, &netlen, 4);
    708         memcpy(netdata+4, data, datalen);
    709         
    710         writed = writen(connfd, netdata, datalen + 4);
    711         if (writed < (datalen + 4) )
    712         {
    713             if (netdata != NULL) 
    714             {
    715                 free(netdata);
    716                 netdata = NULL;
    717             }
    718             return writed;
    719         }
    720           
    721     }
    722     
    723     if (ret < 0)
    724     {
    725         //失败返回-1,超时返回-1并且errno = ETIMEDOUT
    726         if (ret == -1 && errno == ETIMEDOUT)
    727         {
    728             ret = Sck_ErrTimeOut;
    729             printf("func sckServer_send() mlloc Err:%d
     ", ret);
    730             return ret;
    731         }
    732         return ret;
    733     }
    734     
    735     return ret;
    736 }
    737 //服务器端端接受报文
    738 int sckServer_rev(int  connfd, unsigned char *out, int *outlen,  int timeout)
    739 {
    740         
    741     int        ret = 0;
    742     
    743     if (out==NULL || outlen==NULL)
    744     {
    745         ret = Sck_ErrParam;
    746         printf("func sckClient_rev() timeout , err:%d 
    ", Sck_ErrTimeOut);
    747         return ret;
    748     }
    749     
    750     ret =  read_timeout(connfd, timeout); //bugs modify bombing
    751     if (ret != 0)
    752     {
    753         if (ret==-1 || errno == ETIMEDOUT)
    754         {
    755             ret = Sck_ErrTimeOut;
    756             printf("func sckClient_rev() timeout , err:%d 
    ", Sck_ErrTimeOut);
    757             return ret;
    758         }
    759         else
    760         {
    761             printf("func sckClient_rev() timeout , err:%d 
    ", Sck_ErrTimeOut);
    762             return ret;
    763         }    
    764     }
    765     
    766     int netdatalen = 0;
    767     ret = readn(connfd, &netdatalen,  4); //读包头 4个字节
    768     if (ret == -1)
    769     {
    770         printf("func readn() err:%d 
    ", ret);
    771         return ret;
    772     }
    773     else if (ret < 4)
    774     {
    775         ret = Sck_ErrPeerClosed;
    776         printf("func readn() err peer closed:%d 
    ", ret);
    777         return ret;
    778     }
    779     
    780     int n;
    781     n = ntohl(netdatalen);
    782     ret = readn(connfd, out, n); //根据长度读数据
    783     if (ret == -1)
    784     {
    785         printf("func readn() err:%d 
    ", ret);
    786         return ret;
    787     }
    788     else if (ret < n)
    789     {
    790         ret = Sck_ErrPeerClosed;
    791         printf("func readn() err peer closed:%d 
    ", ret);
    792         return ret;
    793     }
    794     
    795     *outlen = n;
    796     
    797     return 0;
    798 }
    799 
    800 //服务器端环境释放 
    801 int sckServer_destroy(void *handle)
    802 {
    803     return 0;
    804 }

     select优化服务器:

      1 #include <unistd.h>
      2 #include <sys/types.h>
      3 #include <sys/socket.h>
      4 #include <netinet/in.h>
      5 #include <arpa/inet.h>
      6 #include <signal.h>
      7 #include <sys/wait.h>
      8 
      9 #include <stdlib.h>
     10 #include <stdio.h>
     11 #include <errno.h>
     12 #include <string.h>
     13 
     14 #define ERR_EXIT(m) 
     15         do 
     16         { 
     17                 perror(m); 
     18                 exit(EXIT_FAILURE); 
     19         } while(0)
     20 
     21 ssize_t readn(int fd, void *buf, size_t count)
     22 {
     23     size_t nleft = count;
     24     ssize_t nread;
     25     char *bufp = (char*)buf;
     26 
     27     while (nleft > 0)
     28     {
     29         if ((nread = read(fd, bufp, nleft)) < 0)
     30         {
     31             if (errno == EINTR)
     32                 continue;
     33             return -1;
     34         }
     35         else if (nread == 0)
     36             return count - nleft;
     37 
     38         bufp += nread;
     39         nleft -= nread;
     40     }
     41 
     42     return count;
     43 }
     44 
     45 ssize_t writen(int fd, const void *buf, size_t count)
     46 {
     47     size_t nleft = count;
     48     ssize_t nwritten;
     49     char *bufp = (char*)buf;
     50 
     51     while (nleft > 0)
     52     {
     53         if ((nwritten = write(fd, bufp, nleft)) < 0)
     54         {
     55             if (errno == EINTR)
     56                 continue;
     57             return -1;
     58         }
     59         else if (nwritten == 0)
     60             continue;
     61 
     62         bufp += nwritten;
     63         nleft -= nwritten;
     64     }
     65 
     66     return count;
     67 }
     68 
     69 ssize_t recv_peek(int sockfd, void *buf, size_t len)
     70 {
     71     while (1)
     72     {
     73         int ret = recv(sockfd, buf, len, MSG_PEEK);
     74         if (ret == -1 && errno == EINTR)
     75             continue;
     76         return ret;
     77     }
     78 }
     79 
     80 ssize_t readline(int sockfd, void *buf, size_t maxline)
     81 {
     82     int ret;
     83     int nread;
     84     char *bufp = buf;
     85     int nleft = maxline;
     86     while (1)
     87     {
     88         ret = recv_peek(sockfd, bufp, nleft);
     89         if (ret < 0)
     90             return ret;
     91         else if (ret == 0)
     92             return ret;
     93 
     94         nread = ret;
     95         int i;
     96         for (i=0; i<nread; i++)
     97         {
     98             if (bufp[i] == '
    ')
     99             {
    100                 ret = readn(sockfd, bufp, i+1);
    101                 if (ret != i+1)
    102                     exit(EXIT_FAILURE);
    103 
    104                 return ret;
    105             }
    106         }
    107 
    108         if (nread > nleft)
    109             exit(EXIT_FAILURE);
    110 
    111         nleft -= nread;
    112         ret = readn(sockfd, bufp, nread);
    113         if (ret != nread)
    114             exit(EXIT_FAILURE);
    115 
    116         bufp += nread;
    117     }
    118 
    119     return -1;
    120 }
    121 
    122 void echo_srv(int conn)
    123 {
    124     char recvbuf[1024];
    125         while (1)
    126         {
    127                 memset(recvbuf, 0, sizeof(recvbuf));
    128                 int ret = readline(conn, recvbuf, 1024);
    129         if (ret == -1)
    130             ERR_EXIT("readline");
    131         if (ret == 0)
    132         {
    133             printf("client close
    ");
    134             break;
    135         }
    136         
    137                 fputs(recvbuf, stdout);
    138                 writen(conn, recvbuf, strlen(recvbuf));
    139         }
    140 }
    141 
    142 void handle_sigchld(int sig)
    143 {
    144 /*    wait(NULL);*/
    145     while (waitpid(-1, NULL, WNOHANG) > 0)
    146         ;
    147 }
    148 
    149 void handle_sigpipe(int sig)
    150 {
    151     printf("recv a sig=%d
    ", sig);
    152 }
    153 
    154 int main(void)
    155 {
    156     /*signal(SIGPIPE, SIG_IGN);*/
    157     signal(SIGPIPE, handle_sigpipe);
    158 /*    signal(SIGCHLD, SIG_IGN);*/
    159     signal(SIGCHLD, handle_sigchld);
    160     int listenfd;
    161     if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    162 /*    if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)*/
    163         ERR_EXIT("socket");
    164 
    165     struct sockaddr_in servaddr;
    166     memset(&servaddr, 0, sizeof(servaddr));
    167     servaddr.sin_family = AF_INET;
    168     servaddr.sin_port = htons(5188);
    169     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    170     /*servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");*/
    171     /*inet_aton("127.0.0.1", &servaddr.sin_addr);*/
    172 
    173     int on = 1;
    174     if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
    175         ERR_EXIT("setsockopt");
    176 
    177     if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
    178         ERR_EXIT("bind");
    179     if (listen(listenfd, SOMAXCONN) < 0)
    180         ERR_EXIT("listen");
    181 
    182     struct sockaddr_in peeraddr;
    183     socklen_t peerlen;    
    184     int conn;
    185 
    186 /*
    187     pid_t pid;
    188     while (1)
    189     {
    190         if ((conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0)
    191             ERR_EXIT("accept");
    192 
    193         printf("ip=%s port=%d
    ", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
    194 
    195         pid = fork();
    196         if (pid == -1)
    197             ERR_EXIT("fork");
    198         if (pid == 0)
    199         {
    200             close(listenfd);
    201             echo_srv(conn);
    202             exit(EXIT_SUCCESS);
    203         }
    204         else
    205             close(conn);
    206     }
    207 */
    208 
    209     int i;
    210     int client[FD_SETSIZE]; //支持的最大客户端连接数 数组
    211     int maxi = 0; //最大的不空闲的位置
    212 
    213     printf("FD_SETSIZE:%d 
    ", FD_SETSIZE);
    214     for (i=0; i<FD_SETSIZE; i++)
    215         client[i] = -1;
    216 
    217     int nready;
    218     int maxfd = listenfd;
    219     fd_set         rset;
    220     fd_set         allset;
    221     
    222     FD_ZERO(&rset);
    223     FD_ZERO(&allset);
    224     FD_SET(listenfd, &allset);
    225     printf("FD_SETSIZE:%d 
    ", FD_SETSIZE);
    226     while (1)
    227     {
    228         rset = allset;
    229         //listenfd 可读,表示有客户端连接进来了,可以建立一个新的连接
    230         nready = select(maxfd+1, &rset, NULL, NULL, NULL);
    231         if (nready == -1)
    232         {
    233             if (errno == EINTR)
    234                 continue;
    235             
    236             ERR_EXIT("select");
    237         }
    238         if (nready == 0)
    239             continue;
    240 
    241         if (FD_ISSET(listenfd, &rset)) //若侦听套接口产生可读事件 说明3次握手已完成,有客户端已经连接建立
    242         {
    243             peerlen = sizeof(peeraddr);
    244             conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen); //处理accept
    245             if (conn == -1)
    246                 ERR_EXIT("accept");
    247 
    248             for (i=0; i<FD_SETSIZE; i++)
    249             {
    250                 if (client[i] < 0)
    251                 {
    252                     client[i] = conn;
    253                     if (i > maxi)
    254                         maxi = i;
    255                     break;
    256                 }
    257             }
    258 
    259             if (i == FD_SETSIZE)
    260             {
    261                 fprintf(stderr, "too many clients
    ");
    262                 exit(EXIT_FAILURE);
    263             }
    264             printf("ip=%s port=%d
    ", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
    265             
    266             FD_SET(conn, &allset); //把新的连接 放入集合中
    267             if (conn > maxfd)  //同时按照条件,更新maxfd  //维护最大描述符
    268                 maxfd = conn;
    269 
    270             if (--nready <= 0)
    271                 continue;
    272 
    273         }
    274 
    275         for (i=0; i<=maxi; i++) //检测已连接的调节字conn是否可读
    276         {
    277             conn = client[i];
    278             if (conn == -1)
    279                 continue;
    280 
    281             if (FD_ISSET(conn, &rset)) //当前连接是否可读
    282             {
    283                 char recvbuf[1024] = {0};
    284                 int ret = readline(conn, recvbuf, 1024);
    285                 if (ret == -1)
    286                         ERR_EXIT("readline");
    287                 if (ret == 0)
    288                 {
    289                     printf("client close
    ");
    290                     FD_CLR(conn, &allset); //若对方已退出 从集合中清除
    291                     client[i] = -1; //保存连接的数组 也置成-1 //也可进一步控制 若i是把maxfd,需要把maxifd变成第二大maxifd
    292                     close(conn);
    293                 }
    294 
    295                 fputs(recvbuf, stdout);
    296                 //sleep(4);
    297                 writen(conn, recvbuf, strlen(recvbuf));
    298 
    299                 if (--nready <= 0)
    300                     break;    
    301             }
    302         }
    303     }    
    304     return 0;
    305 }

    select优化客户端:

      1 #include <unistd.h>
      2 #include <sys/types.h>
      3 #include <sys/socket.h>
      4 #include <netinet/in.h>
      5 #include <arpa/inet.h>
      6 #include <signal.h>
      7 
      8 #include <stdlib.h>
      9 #include <stdio.h>
     10 #include <errno.h>
     11 #include <string.h>
     12 
     13 #define ERR_EXIT(m) 
     14         do 
     15         { 
     16                 perror(m); 
     17                 exit(EXIT_FAILURE); 
     18         } while(0)
     19 
     20 ssize_t readn(int fd, void *buf, size_t count)
     21 {
     22         size_t nleft = count;
     23         ssize_t nread;
     24         char *bufp = (char*)buf;
     25 
     26         while (nleft > 0)
     27         {
     28                 if ((nread = read(fd, bufp, nleft)) < 0)
     29                 {
     30                         if (errno == EINTR)
     31                                 continue;
     32                         return -1;
     33                 }
     34                 else if (nread == 0)
     35                         return count - nleft;
     36 
     37                 bufp += nread;
     38                 nleft -= nread;
     39         }
     40 
     41         return count;
     42 }
     43 
     44 ssize_t writen(int fd, const void *buf, size_t count)
     45 {
     46         size_t nleft = count;
     47         ssize_t nwritten;
     48         char *bufp = (char*)buf;
     49 
     50         while (nleft > 0)
     51         {
     52                 if ((nwritten = write(fd, bufp, nleft)) < 0)
     53                 {
     54                         if (errno == EINTR)
     55                                 continue;
     56                         return -1;
     57                 }
     58                 else if (nwritten == 0)
     59                         continue;
     60 
     61                 bufp += nwritten;
     62                 nleft -= nwritten;
     63         }
     64 
     65         return count;
     66 }
     67 
     68 ssize_t recv_peek(int sockfd, void *buf, size_t len)
     69 {
     70         while (1)
     71         {
     72                 int ret = recv(sockfd, buf, len, MSG_PEEK);
     73                 if (ret == -1 && errno == EINTR)
     74                         continue;
     75                 return ret;
     76         }
     77 }
     78 
     79 
     80 ssize_t readline(int sockfd, void *buf, size_t maxline)
     81 {
     82         int ret;
     83         int nread;
     84         char *bufp = buf;
     85         int nleft = maxline;
     86         while (1)
     87         {
     88                 ret = recv_peek(sockfd, bufp, nleft);
     89                 if (ret < 0)
     90                         return ret;
     91                 else if (ret == 0)
     92                         return ret;
     93 
     94                 nread = ret;
     95                 int i;
     96                 for (i=0; i<nread; i++)
     97                 {
     98                         if (bufp[i] == '
    ')
     99                         {
    100                                 ret = readn(sockfd, bufp, i+1);
    101                                 if (ret != i+1)
    102                                         exit(EXIT_FAILURE);
    103 
    104                                 return ret;
    105                         }
    106                 }
    107 
    108                 if (nread > nleft)
    109                         exit(EXIT_FAILURE);
    110 
    111                 nleft -= nread;
    112                 ret = readn(sockfd, bufp, nread);
    113                 if (ret != nread)
    114                         exit(EXIT_FAILURE);
    115 
    116                 bufp += nread;
    117         }
    118 
    119         return -1;
    120 }
    121 
    122 void echo_cli(int sock)
    123 {
    124 /*
    125     char sendbuf[1024] = {0};
    126         char recvbuf[1024] = {0};
    127         while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
    128         {
    129                 writen(sock, sendbuf, strlen(sendbuf));
    130 
    131                 int ret = readline(sock, recvbuf, sizeof(recvbuf));
    132                 if (ret == -1)
    133                         ERR_EXIT("readline");
    134                 else if (ret == 0)
    135                 {
    136                         printf("client close
    ");
    137                         break;
    138                 }
    139 
    140                 fputs(recvbuf, stdout);
    141                 memset(sendbuf, 0, sizeof(sendbuf));
    142                 memset(recvbuf, 0, sizeof(recvbuf));
    143         }
    144 
    145         close(sock);
    146 */
    147     fd_set     rset;
    148     FD_ZERO(&rset);
    149 
    150     int     nready;
    151     int     maxfd;
    152     int         fd_stdin = fileno(stdin);
    153     
    154     if (fd_stdin > sock)
    155         maxfd = fd_stdin;
    156     else
    157         maxfd = sock;
    158 
    159     char sendbuf[1024] = {0};
    160     char recvbuf[1024] = {0};
    161 
    162     while (1)
    163     {
    164         FD_SET(fd_stdin, &rset);
    165         FD_SET(sock, &rset);
    166         nready = select(maxfd+1, &rset, NULL, NULL, NULL);
    167         if (nready == -1)
    168             ERR_EXIT("select");
    169 
    170         if (nready == 0)
    171             continue;
    172 
    173         if (FD_ISSET(sock, &rset))
    174         {
    175             int ret = readline(sock, recvbuf, sizeof(recvbuf));
    176             if (ret == -1)
    177                     ERR_EXIT("readline");
    178             else if (ret == 0)
    179             {
    180                 printf("server close
    ");
    181                 break;
    182             }
    183 
    184                fputs(recvbuf, stdout);
    185             memset(recvbuf, 0, sizeof(recvbuf));
    186         }
    187         if (FD_ISSET(fd_stdin, &rset))
    188         {
    189             if (fgets(sendbuf, sizeof(sendbuf), stdin) == NULL)
    190                 break;
    191             writen(sock, sendbuf, strlen(sendbuf));
    192             memset(sendbuf, 0, sizeof(sendbuf));
    193         }
    194     }
    195 
    196     close(sock);
    197 }
    198 
    199 void handle_sigpipe(int sig)
    200 {
    201     printf("recv a sig=%d
    ", sig);
    202 }
    203 
    204 int main(void)
    205 {
    206 /*
    207     signal(SIGPIPE, handle_sigpipe);
    208 */
    209     signal(SIGPIPE, SIG_IGN);
    210     int sock;
    211     if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    212         ERR_EXIT("socket");
    213 
    214     struct sockaddr_in servaddr;
    215     memset(&servaddr, 0, sizeof(servaddr));
    216     servaddr.sin_family = AF_INET;
    217     servaddr.sin_port = htons(5188);
    218     servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    219 
    220     if (connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
    221         ERR_EXIT("connect");
    222 
    223     struct sockaddr_in localaddr;
    224     socklen_t addrlen = sizeof(localaddr);
    225     if (getsockname(sock, (struct sockaddr*)&localaddr, &addrlen) < 0)
    226         ERR_EXIT("getsockname");
    227 
    228     printf("ip=%s port=%d
    ", inet_ntoa(localaddr.sin_addr), ntohs(localaddr.sin_port));
    229 
    230 
    231     echo_cli(sock);
    232 
    233     return 0;
    234 }
  • 相关阅读:
    数据处理:并行和性能 狼人:
    GTK+3.0终发布:诸多新特性亮相 狼人:
    微软:Windows 7 SP1将于本月正式发布 狼人:
    程序员的进化 狼人:
    TDD并不是看上去的那么美 狼人:
    Bing API 将新增 Bing 空间数据服务 狼人:
    微软产品组里的十一类人 狼人:
    Windows Phone 7“芒果”更新带来浏览器重大升级:IE Mobile 9 狼人:
    UI前沿技术:XNA颜色滚动程序 狼人:
    传递拷贝php 数组 传递 引用
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9419849.html
Copyright © 2011-2022 走看看