流协议与粘包

  • TCP:基于字节流的传输服务,无边界,不能保证对等方一次接受能能够返回好多字节
  • UDP:基于消息的传输服务,传输数据包有边界
  • 粘包产生的原因:
  • 粘包解决方案:
    • 定长包
    • 包尾加 (ftp)
    • 包头加上包体长度
    • 更复杂的应用层协议
  • readn writen(广域网必须处理粘包问题)
    • service
      •   1 #include <stdio.h>
          2 #include <errno.h>
          3 #include <string.h>
          4 #include <stdlib.h>
          5 #include <unistd.h>
          6 #include <sys/types.h>
          7 #include <sys/socket.h>
          8 #include <netinet/in.h>
          9 #include <arpa/inet.h>
         10 
         11 #define ERR_EXIT(m)
         12     do{
         13         perror(m);
         14         exit(EXIT_FAILURE);
         15     }while(0)
         16 
         17 struct packet
         18 {
         19     int len;
         20     char buf[1024];
         21 };
         22 
         23 ssize_t readn(int fd, void* buf,size_t count)
         24 {
         25     size_t nleft = count;
         26     ssize_t nread;
         27     char *bufp = (char*)buf;
         28     
         29     while(nleft > 0)
         30     {
         31         if((nread = read(fd,bufp,nleft)) < 0)
         32         {
         33             if(errno == EINTR)
         34                 continue;
         35             return -1;
         36         }
         37         else if(nread == 0)
         38         {
         39             return count-nleft;
         40         }
         41         
         42         bufp += nread;
         43         nleft -= nread;
         44     }
         45     return count;
         46 }
         47 
         48 ssize_t writen(int fd, void* buf,size_t count)
         49 {
         50     size_t nleft = count;
         51     ssize_t nwrite;
         52     char *bufp = (char*)buf;
         53     
         54     while(nleft > 0)
         55     {
         56         if((nwrite = write(fd,bufp,nleft)) < 0)
         57         {
         58             if (errno = EINTR)
         59                 continue;
         60             return -1;
         61         }
         62         else if(nwrite == 0)
         63             continue;
         64         bufp += nwrite;
         65         nleft -= nwrite;
         66     }    
         67     return count;
         68 }
         69 
         70 void do_service(int conn)
         71 {
         72 //    char recvbuf[1024];
         73     struct packet recvbuf;
         74     int n;
         75     while(1)
         76     {
         77         memset(&recvbuf,0,sizeof(recvbuf));
         78         int ret = readn(conn,&recvbuf.len,4);
         79         if(ret < 4)
         80         {
         81             printf("client close
        ");
         82             break;
         83         }
         84         else if(ret == -1)
         85             ERR_EXIT("read");
         86         n = ntohl(recvbuf.len);
         87         ret = readn(conn,&recvbuf.buf,n);
         88         if(ret == -1)
         89             ERR_EXIT("read");
         90         else if(ret < n)
         91         {
         92             printf("client close
        ");
         93             break;
         94         }
         95                 
         96         fputs(recvbuf.buf,stdout);
         97         writen(conn,&recvbuf,n+4);
         98     }
         99 }
        100 
        101 int main(void)
        102 {
        103     int listenfd;
        104     if((listenfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
        105         ERR_EXIT("socket");
        106 
        107     struct sockaddr_in servaddr;
        108     memset(&servaddr, 0, sizeof(servaddr));
        109     servaddr.sin_family = AF_INET;
        110     servaddr.sin_port = htons(5188);
        111     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        112 
        113     int on;
        114     if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
        115         ERR_EXIT("setsockopt");
        116     if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)
        117         ERR_EXIT("bind");
        118     if(listen(listenfd,SOMAXCONN) < 0)
        119         ERR_EXIT("listen");
        120     struct sockaddr_in peeraddr;
        121     socklen_t peerlen = sizeof(peeraddr);
        122     int conn;
        123 
        124     pid_t pid;
        125     while(1)
        126     {
        127         if((conn = accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen)) < 0)
        128             ERR_EXIT("accept");
        129         printf("ip=%s,port=%d	
        ",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));
        130 
        131         pid = fork();
        132         if(pid == -1)
        133             ERR_EXIT("fork");
        134         if(pid == 0)
        135         {
        136             close(listenfd);
        137             do_service(conn);
        138             exit(EXIT_SUCCESS);
        139         }
        140         else
        141             close(conn);
        142     }
        143     return 0;    
        144 }
        View Code
    • client
      •   
          1 #include <stdio.h>
          2 #include <errno.h>
          3 #include <string.h>
          4 #include <stdlib.h>
          5 #include <unistd.h>
          6 #include <sys/types.h>
          7 #include <sys/socket.h>
          8 #include <netinet/in.h>
          9 #include <arpa/inet.h>
         10 
         11 #define ERR_EXIT(m)
         12     do{
         13         perror(m);
         14         exit(EXIT_FAILURE);
         15     }while(0)
         16 
         17 ssize_t readn(int fd, void* buf,size_t count)
         18 {
         19     size_t nleft = count;
         20     ssize_t nread;
         21     char *bufp = (char*)buf;
         22     
         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         {
         33             return count-nleft;
         34         }
         35         
         36         bufp += nread;
         37         nleft -= nread;
         38     }
         39     return count;
         40 }
         41 
         42 ssize_t writen(int fd, void* buf,size_t count)
         43 {
         44     size_t nleft = count;
         45     ssize_t nwrite;
         46     char *bufp = (char*)buf;
         47     
         48     while(nleft > 0)
         49     {
         50         if((nwrite = write(fd,bufp,nleft)) < 0)
         51         {
         52             if (errno = EINTR)
         53                 continue;
         54             return -1;
         55         }
         56         else if(nwrite == 0)
         57             continue;
         58         bufp += nwrite;
         59         nleft -= nwrite;
         60     }    
         61     return count;
         62 }
         63 
         64 void do_service(int conn)
         65 {
         66     char recvbuf[1024];
         67     while(1)
         68     {
         69         memset(recvbuf,0,sizeof(recvbuf));
         70         int ret = read(conn,recvbuf,sizeof(recvbuf));
         71         if(ret ==0)
         72         {
         73             printf("client close
        ");
         74             break;
         75         }
         76         else if(ret == -1)
         77             ERR_EXIT("read");
         78         fputs(recvbuf,stdout);
         79         write(conn,recvbuf,ret);
         80     }
         81 }
         82 
         83 struct packet
         84 {
         85     int len;
         86     char buf[1024];
         87 };
         88 
         89 int main(void)
         90 {
         91     int sock;
         92     if((sock= socket(AF_INET,SOCK_STREAM,0)) < 0)
         93         ERR_EXIT("socket");
         94 
         95     struct sockaddr_in servaddr;
         96     memset(&servaddr, 0, sizeof(servaddr));
         97     servaddr.sin_family = AF_INET;
         98     servaddr.sin_port = htons(5188);
         99     servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
        100 
        101     if(connect(sock,(struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
        102         ERR_EXIT("connect");
        103 
        104     struct packet sendbuf;
        105     struct packet recvbuf;
        106     memset(&sendbuf,0,sizeof(sendbuf));
        107     memset(&recvbuf,0,sizeof(recvbuf));
        108 
        109 //    char sendbuf[1024] = { 0 };
        110 //    char recvbuf[1024] = { 0 };
        111     int n;
        112     while(fgets(sendbuf.buf,sizeof(sendbuf.buf),stdin) != NULL)
        113     {
        114         n = strlen(sendbuf.buf);
        115         
        116         sendbuf.len =htonl(n);
        117         writen(sock,&sendbuf.len,4+n);
        118         //writen(sock,sendbuf,strlen(sendbuf));
        119         int ret = readn(sock,&recvbuf.len,4);
        120         if(ret == -1)
        121             ERR_EXIT("readn");
        122         else if(ret < 4)
        123         {
        124             printf("client close");
        125             break;
        126         }
        127         n = ntohl(sendbuf.len);
        128         ret = readn(sock,&recvbuf.buf,n);
        129         if(ret == -1)
        130             ERR_EXIT("readn");
        131         else if(ret < n)
        132         {
        133             printf("client close
        ");
        134             break;
        135         }
        136         
        137         fputs(recvbuf.buf,stdout);
        138 //        fputs(recvbuf,stdout);
        139 
        140         memset(&sendbuf,0, sizeof(sendbuf));
        141         memset(&recvbuf,0, sizeof(recvbuf));
        142     }
        143     close(sock);
        144     return 0;    
        145 }
        View Code
作者:长风 Email:844064492@qq.com QQ群:607717453 Git:https://github.com/zhaohu19910409Dz 开源项目:https://github.com/OriginMEK/MEK 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利. 感谢您的阅读。如果觉得有用的就请各位大神高抬贵手“推荐一下”吧!你的精神支持是博主强大的写作动力。 如果觉得我的博客有意思,欢迎点击首页左上角的“+加关注”按钮关注我!
原文地址:https://www.cnblogs.com/zhaohu/p/8962006.html