zoukankan      html  css  js  c++  java
  • 自己封装一个readline函数实现服务器客户端回射

    实现的功能:一次只能读取一行,客户端输入之后,一回车,马上字符串传到服务器端并显示在终端,然后服务器端将字符串又传回给客户端。

          服务器端可以接收多个客户端的连接请求,并fork一个子进程来进行服务。

    (1)封装一个只能访问套接字描述符的readline函数

    (2)服务器端启动SO_REUSEADDR套接字选项,以便服务器端不必等待TIME_WAIT状态

    这是服务器端代码:

      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<stdlib.h>
      7 #include<stdio.h>
      8 #include<errno.h>
      9 #include<string.h>
     10 
     11 #define ERR_EXIT(m) 
     12         do 
     13         { 
     14             perror(m); 
     15             exit(EXIT_FAILURE);
     16         }while(0)
     17 
     18 void do_service(int conn)
     19 {
     20     char recvbuf[1024];
     21     while(1)
     22     {
     23         memset(recvbuf,0,sizeof(recvbuf));
     24         int ret=readline(conn,recvbuf,sizeof(recvbuf));
     25         if(-1==ret)
     26             ERR_EXIT("readline in do_servece");
     27         else if(0==ret)
     28         {
     29             printf("client close
    ");
     30             break;
     31         }
     32         fputs(recvbuf,stdout);
     33         writen(conn,recvbuf,strlen(recvbuf));
     34     }
     35 }
     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     while(nleft>0)
     43     {
     44         if((nread=read(fd,bufp,nleft))<0)
     45         {
     46             if(errno==EINTR)
     47                 continue;
     48             return -1;
     49         }
     50         else if(nread==0)
     51             return count-nleft;
     52         bufp+=nread;
     53         nleft-=nread;
     54     }
     55     return count;
     56 }
     57 
     58 ssize_t writen(int fd,const void*buf,size_t count)
     59 {
     60     size_t nleft=count;
     61     ssize_t nwritten;
     62     char*bufp=(char*)buf;
     63     while(nleft>0)
     64     {
     65         if((nwritten=write(fd,bufp,nleft))<0)
     66         {
     67             if(errno==EINTR)
     68                 continue;
     69             return -1;
     70         }
     71         else if(nwritten==0)
     72             continue;
     73         bufp+=nwritten;
     74         nleft-=nwritten;
     75     }
     76     return count;
     77 }
     78 
     79 ssize_t recv_peek(int sockfd,void *buf,size_t len)
     80 {
     81     while(1)
     82     {
     83         int ret=recv(sockfd,buf,len,MSG_PEEK);//窥看,不清除缓存中的数据
     84         if(-1==ret&&EINTR==errno)
     85             continue;
     86         return ret;
     87     }
     88 }
     89 
     90 ssize_t readline(int sockfd,void* buf,size_t maxline)
     91 {
     92     int ret;
     93     int nread;
     94     char* bufp=(char*)buf;
     95     int nleft=maxline;
     96     while(1)
     97     {
     98         ret=recv_peek(sockfd,bufp,nleft);
     99         if(ret<0)
    100             return ret;
    101         else if(0==ret)
    102             return ret;
    103         nread=ret;
    104         int i;
    105         for(i=0;i<nread;i++)//读取到'
    '时就应该结束
    106         {
    107             if(bufp[i]=='
    ')
    108             {
    109                 ret=readn(sockfd,bufp,i+1);
    110                 if(ret!=i+1)
    111                     exit(EXIT_FAILURE);
    112                 return ret;
    113             }
    114         }
    115         //执行到了这儿,说明没有读取到'
    '
    116         if(nread>nleft)
    117             exit(EXIT_FAILURE);
    118         nleft-=nread;
    119         ret=readn(sockfd,bufp,nread);//清空缓存中的数据,因为之前是窥视,并没有清空缓存
    120         if(ret!=nread)
    121             exit(EXIT_FAILURE);
    122         bufp+=nread;//指针后移,接着去执行while循环,确保数据追加到原来已读取数据的末尾
    123     }
    124     return -1;
    125 }        
    126 int main(void)
    127 {
    128     int listenfd;
    129     if((listenfd=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0)
    130         ERR_EXIT("socket");
    131     
    132     struct sockaddr_in servaddr;
    133     memset(&servaddr,0,sizeof(servaddr));
    134     servaddr.sin_family=AF_INET;
    135     servaddr.sin_port=htons(5188);
    136     servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
    137     //套接字选项的设置一定要在bind之前
    138     int on=1;
    139     if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))<0)
    140             ERR_EXIT("setsockopt");
    141     if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
    142         ERR_EXIT("bind");
    143     if(listen(listenfd,SOMAXCONN)<0)
    144         ERR_EXIT("listen");
    145     struct sockaddr_in peeraddr;
    146     socklen_t peerlen=sizeof(peeraddr);
    147     int conn;
    148     pid_t pid;
    149     while(1)
    150     {
    151         if((conn=accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen))<0)
    152             ERR_EXIT("accept");
    153         printf("ip=%s port=%d
    ",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));
    154         pid=fork();
    155         if(-1==pid)
    156             ERR_EXIT("fork");
    157         if(0==pid)//子进程
    158         {
    159             close(listenfd);
    160             do_service(conn);
    161             exit(EXIT_SUCCESS);
    162         }
    163         else close(conn);//父进程
    164     }
    165     
    166     
    167     return 0;
    168 }    
    169         
    170 
    171 
    172 
    173         

    这是客户端代码:

      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<stdlib.h>
      7 #include<stdio.h>
      8 #include<errno.h>
      9 #include<string.h>
     10 
     11 #define ERR_EXIT(m) 
     12         do 
     13         { 
     14             perror(m); 
     15             exit(EXIT_FAILURE);
     16         }while(0)
     17             
     18 ssize_t readn(int fd,void *buf,size_t count)
     19 {
     20     size_t nleft=count;
     21     ssize_t nread;
     22     char*bufp=(char*)buf;
     23     while(nleft>0)
     24     {
     25         if((nread=read(fd,bufp,nleft))<0)
     26         {
     27             if(errno==EINTR)
     28                 continue;
     29             return -1;
     30         }
     31         else if(nread==0)
     32             return count-nleft;
     33         bufp+=nread;
     34         nleft-=nread;
     35     }
     36     return count;
     37 }
     38 
     39 ssize_t writen(int fd,const void*buf,size_t count)
     40 {
     41     size_t nleft=count;
     42     ssize_t nwritten;
     43     char*bufp=(char*)buf;
     44     while(nleft>0)
     45     {
     46         if((nwritten=write(fd,bufp,nleft))<0)
     47         {
     48             if(errno==EINTR)
     49                 continue;
     50             return -1;
     51         }
     52         else if(nwritten==0)
     53             continue;
     54         bufp+=nwritten;
     55         nleft-=nwritten;
     56     }
     57     return count;
     58 }
     59 
     60 ssize_t recv_peek(int sockfd,void *buf,size_t len)
     61 {
     62     while(1)
     63     {
     64         int ret=recv(sockfd,buf,len,MSG_PEEK);//窥看,不清除缓存中的数据
     65         if(-1==ret&&EINTR==errno)
     66             continue;
     67         return ret;
     68     }
     69 }
     70 
     71 ssize_t readline(int sockfd,void* buf,size_t maxline)
     72 {
     73     int ret;
     74     int nread;
     75     char* bufp=(char*)buf;
     76     int nleft=maxline;
     77     while(1)
     78     {
     79         ret=recv_peek(sockfd,bufp,nleft);
     80         if(ret<0)
     81             return ret;
     82         else if(0==ret)
     83             return ret;
     84         nread=ret;
     85         int i;
     86         for(i=0;i<nread;i++)//读取到'
    '时就应该结束
     87         {
     88             if(bufp[i]=='
    ')
     89             {
     90                 ret=readn(sockfd,bufp,i+1);
     91                 if(ret!=i+1)
     92                     exit(EXIT_FAILURE);
     93                 return ret;
     94             }
     95         }
     96         //执行到了这儿,说明没有读取到'
    '
     97         if(nread>nleft)
     98             exit(EXIT_FAILURE);
     99         nleft-=nread;
    100         ret=readn(sockfd,bufp,nread);//清空缓存中的数据,因为之前是窥视,并没有清空缓存
    101         if(ret!=nread)
    102             exit(EXIT_FAILURE);
    103         bufp+=nread;//指针后移,接着去执行while循环,确保数据追加到原来已读取数据的末尾
    104     }
    105     return -1;
    106 }
    107 int main(void)
    108 {
    109     int sock;
    110     if((sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0)
    111         ERR_EXIT("socket");
    112     struct sockaddr_in servaddr;
    113     memset(&servaddr,0,sizeof(servaddr));
    114     servaddr.sin_family=AF_INET;
    115     servaddr.sin_port=htons(5188);
    116     servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");//inet_addr将ip地址字符串转为数字形式,且已经是网络字节序    
    117     
    118     if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)//
    119         ERR_EXIT("connect");
    120         
    121     char sendbuf[1024]={0};
    122     char recvbuf[1024]={0};
    123     while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)
    124     {
    125         writen(sock,sendbuf,strlen(sendbuf));
    126         
    127         int ret=readline(sock,recvbuf,sizeof(recvbuf));
    128         if(-1==ret)
    129             ERR_EXIT("readline");
    130         else if(0==ret)
    131         {
    132             printf("client?server close
    ");
    133             break;
    134         }
    135         fputs(recvbuf,stdout);
    136     }
    137     
    138     return 0;
    139 }
    手里拿着一把锤子,看什么都像钉子,编程界的锤子应该就是算法了吧!
  • 相关阅读:
    Android ANR异常解决方案
    数据结构之斐波那契查找
    数据结构之插值查找
    数据结构之折半查找
    Android Task 任务
    java中“==”号的运用
    php中向前台js中传送一个二维数组
    array_unique和array_flip 实现去重间的区别
    js new Date() 获取时间
    手机端html5触屏事件(touch事件)
  • 原文地址:https://www.cnblogs.com/chess/p/4684053.html
Copyright © 2011-2022 走看看