• tcp/ip通信第5期之服务器端程序


      1 /*
      2 此程序是tcp/ip通信服务器端程序,测试运行在redhat5上
      3 重构readline函数,解决粘包问题——利用“
    ”识别一个消息边界
      4 */
      5 
      6 #include<stdio.h>
      7 #include<netinet/in.h>
      8 #include<arpa/inet.h>
      9 #include<unistd.h>
     10 #include<fcntl.h>
     11 #include<sys/types.h>
     12 #include<sys/stat.h>
     13 #include<sys/socket.h>
     14 #include<stdio.h>
     15 #include<stdlib.h>
     16 #include<string.h>
     17 #include<signal.h>
     18 #include<errno.h>
     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     while (nleft > 0)
     26             {
     27                 if ((nread = read(fd, bufp, nleft)) < 0)
     28                 {
     29                     if (errno == EINTR)
     30  //被信号中断,errno这个全局变量的值就会等于EINTR。
     31                         continue;
     32                     return -1;
     33                 }
     34                 else if (nread == 0) //对方关闭或者已经读到eof
     35                     return count - nleft;
     36                 bufp += nread;
     37                 nleft -= nread;
     38             }
     39             return count;
     40 }
     41      
     42 ssize_t writen(int fd, const void * buf, size_t count) 
     43 {
     44         size_t nleft = count;
     45         ssize_t nwritten;
     46         char *bufp = (char *)buf;
     47         while (nleft > 0)
     48             {
     49                 if ((nwritten = write(fd, bufp, nleft)) < 0)
     50                 {
     51                     if (errno == EINTR)
     52                         continue;
     53  //要保证读取的字节数为指定字节数,所以继续
     54                     return -1;
     55                 }
     56                 else if (nwritten == 0)        
     57                     continue;
     58  //由于其他原因引起的什么都没有写进,则继续操作,保证指定字节数
     59                 bufp += nwritten;
     60                 nleft -= nwritten;
     61             }
     62             return count;
     63 }
     64 
     65 ssize_t recv_peek(int sockfd,void *buf,size_t len)
     66 {
     67     while(1)
     68     {
     69         int ret=recv(sockfd,buf,len,MSG_PEEK);
     70         if(ret==-1&&errno==EINTR)
     71             continue;
     72         return ret;
     73     }
     74 }
     75 
     76 ssize_t recv_line(int sockfd,void *buf,size_t len)
     77 {
     78     int ret;//记录函数返回值
     79     int nread;//已经读到的字节数
     80     char *bufp=buf;
     81     int nleft=len;
     82     while(1)
     83     {
     84         ret=recv_peek(sockfd,bufp,nleft);
     85         if(ret<0)
     86             return ret;
     87         else if(ret==0)
     88             return ret;
     89         nread=ret;
     90         int i;
     91         for(i=0;i<nread;i++)
     92         {
     93             if(bufp[i]=='
    ')
     94             {
     95                 ret=readn(sockfd,bufp,i+1);
     96                 if(ret!=i+1)
     97                     exit(1);
     98                 return ret;
     99             }
    100         }
    101         if(nread>nleft)
    102             exit(1);
    103         nleft -= nread;
    104         ret=readn(sockfd,bufp,nread);
    105         if(ret!=nread)
    106             exit(0);
    107         bufp+=nread;
    108     }
    109     return -1;
    110 }
    111 
    112 
    113 #define port 5188
    114 int main()
    115 {
    116     int listenfd;
    117     //*****创建套接字*******
    118     if((listenfd=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0)
    119     /*if((listenfd=socket(PF_INET,SOCK_STREAM,0))<0)*/
    120         perror("error");
    121         
    122     //*******ipv4地址结构**********
    123     struct sockaddr_in servaddr;
    124     memset(&servaddr,0,sizeof(servaddr)); //清空结构体变量
    125     servaddr.sin_family=AF_INET;
    126     servaddr.sin_port=htons(port); //使用端口号:5188
    127     servaddr.sin_addr.s_addr=htonl(INADDR_ANY);//INADDR_ANY表示使用本机的任意可用ip地址,转换成网络地址序
    128     /*servaddr.sin_addr.s_addr = inet_addr("127.168.0.12");*/
    129     /*inet_aton("127.168.0.12",&servaddr.sin_addr);*/
    130     
    131     //*******绑定套接字和本机地址***********
    132     //1、设置REUSEADDR选项
    133     int N=1;
    134     if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&N,sizeof(N))<0)
    135         perror("error");
    136     //2、进行绑定
    137     if(bind(listenfd,(struct sockaddr*)(&servaddr),sizeof(struct sockaddr))<0)
    138         perror("error");
    139     
    140     //********将绑定的套接字转换为监听状态********
    141     if(listen(listenfd,SOMAXCONN)<0) //SOMAXCONN这个宏表示最大队列值
    142         perror("error");
    143     /*一旦调用listen函数,那么这个套接字就变成了被动套接字(只能被动接受连接——accept,
    144       不能发起连接——connect),否则还是主动套接字(可以发起连接——connect)*/
    145     
    146     //********接收对方的连接请求**************
    147     struct sockaddr_in peeraddr;  //定义对方地址
    148     socklen_t peerlen=sizeof(peeraddr);
    149     int con;
    150     if((con=accept(listenfd,(struct sockaddr*)(&peeraddr),&peerlen))<0)
    151         perror("error");
    152     else
    153         printf("client_ip=%s,client_port=%d
    ",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));
    154     
    155     //*******数据通信过程***********
    156     char recvbuf[1024];
    157     while(1)
    158     {
    159         memset(recvbuf,0,sizeof(recvbuf));
    160         int ret=recv_line(con,recvbuf,sizeof(recvbuf));//con这里是已连接套接字,不再是被动套接字,而是主动套接字了
    161         if(ret==-1)
    162             exit(1);
    163         if(ret==0)
    164         {
    165             printf("client_port is closed.
    ");
    166             break;
    167         }
    168         fputs(recvbuf,stdout);
    169         writen(con,recvbuf,strlen(recvbuf));
    170         memset(recvbuf,0,sizeof(recvbuf));
    171     }
    172     close(con);
    173     close(listenfd);
    174     return 0;
    175     
    176 }
    内在的趣味,表面的繁琐
  • 相关阅读:
    codevs1288 埃及分数
    codevs1792 分解质因数
    dp
    JAVA大数贪心
    求最长不重叠子串
    初识后缀数组
    dp
    两数相除,判断小数位是否有限位
    构造二分图匹配
    建立多个树状数组
  • 原文地址:https://www.cnblogs.com/data1213/p/4815858.html
Copyright © 2020-2023  润新知