【转】TCP粘包问题解决方法之\n\r

时间:2022-05-14 19:27:24

该方案,每次读取时当读到‘\n’换行符时,读取该行

服务器端:

[cpp]  view plain  copy
  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. #define ERR_EXIT(m) do{perror(m);exit(EXIT_FAILURE);}while(1)  
  11. struct packet  
  12. {  
  13.     int len;  
  14.     char buf[1024];  
  15. };  
  16. ssize_t readn(int fd, void *buf, size_t count)  
  17. {  
  18.     size_t nleft = count;  
  19.     ssize_t nread;  
  20.     char *bufp = (char*)buf;  
  21.     while (nleft > 0)  
  22.     {  
  23.         if ((nread = read(fd, bufp, nleft)) < 0)  
  24.         {  
  25.             if (errno == EINTR)  
  26.             {  
  27.                 continue;  
  28.                 return -1;  
  29.             }  
  30.             else if (nread == 0)return count - nleft;  
  31.         }  
  32.         bufp = bufp + nread;  
  33.         nleft = nleft - nread;  
  34.     }  
  35.     return count;  
  36. }  
  37. ssize_t writen(int fd, void *buf, size_t count)  
  38. {  
  39.     size_t nleft = count;  
  40.     ssize_t nwrite;  
  41.     char *bufp = (char*)buf;  
  42.     while (nleft > 0)  
  43.     {  
  44.         if ((nwrite = write(fd, bufp, nleft)) < 0)  
  45.         {  
  46.             if (errno == EINTR)  
  47.             {  
  48.                 continue;  
  49.                 return -1;  
  50.             }  
  51.             else if (nwrite == 0)continue;  
  52.         }  
  53.         bufp = bufp + nwrite;  
  54.         nleft = nleft - nwrite;  
  55.     }  
  56.     return count;  
  57. }  
  58. ssize_t recv_peek(int sockfd, void *buf, size_t len)  
  59. {  
  60.     while (1)  
  61.     {  
  62.         int ret = recv(sockfd, buf, len, MSG_PEEK);  
  63.         if (ret == -1 && errno == EINTR)continue;  
  64.         return ret;  
  65.     }  
  66. }  
  67. ssize_t readline(int sockfd, void *buf, size_t maxline)  
  68. {  
  69.     int ret;  
  70.     int nread;  
  71.     char *bufp = (char*)buf;  
  72.     int nleft = maxline;  
  73.     while (1)  
  74.     {  
  75.         ret = recv_peek(sockfd, bufp, nleft);  
  76.         if (ret < 0)return ret;  
  77.         else if (ret == 0)return ret;//对方关闭了套接口  
  78.         nread = ret;  
  79.         for (int i = 0; i < nread; i++)  
  80.         {  
  81.             if (bufp[i] == '\n')  
  82.             {  
  83.                 ret = readn(sockfd, bufp, i + 1);//将缓冲区数据移除  
  84.                 if (ret != i + 1)exit(EXIT_FAILURE);  
  85.                 return ret;  
  86.             }  
  87.         }  
  88.         if (nread>nleft)exit(EXIT_FAILURE);//读到的数据不能超过缓冲区  
  89.         nleft -= nread;  
  90.         ret = readn(sockfd, bufp, nread);  
  91.         if (ret != nread)exit(EXIT_FAILURE);  
  92.         bufp += nread;  
  93.     }  
  94.     return -1;  
  95. }  
  96. void do_service(int connfd)  
  97. {  
  98.     char recvbuf[1024];  
  99.     int n;  
  100.     while (1)  
  101.     {  
  102.         memset(&recvbuf, 0, sizeof(recvbuf));  
  103.         int ret = readline(connfd, recvbuf, 1204);  
  104.         if (ret == -1)  
  105.         {  
  106.             ERR_EXIT("read");  
  107.         }  
  108.         else if (ret ==0 )  
  109.         {  
  110.             printf("client cloase\n");  
  111.             break;  
  112.         }  
  113.         fputs(recvbuf, stdout);  
  114.         writen(connfd, recvbuf, strlen(recvbuf));  
  115.     }  
  116. }  
  117. int main(void)  
  118. {  
  119.     int listenfd;  
  120.     if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)ERR_EXIT("socket");  
  121.     struct sockaddr_in servaddr;  
  122.     memset(&servaddr, 0, sizeof(servaddr));  
  123.     servaddr.sin_family = AF_INET;  
  124.     servaddr.sin_port = htons(5188);  
  125.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
  126.     int on = 1;  
  127.     if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)ERR_EXIT("setsockopt");  
  128.     if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)ERR_EXIT("bind");  
  129.     if (listen(listenfd, SOMAXCONN) < 0)ERR_EXIT("listten");  
  130.     while (1)  
  131.     {  
  132.         int connfd;  
  133.         struct sockaddr_in peeraddr;  
  134.         socklen_t peerlen = sizeof(peeraddr);  
  135.         if ((connfd = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0)ERR_EXIT("accept");  
  136.             printf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));  
  137.             pid_t pid = fork();  
  138.         if (pid == -1)ERR_EXIT("fork");  
  139.         if (pid == 0)  
  140.         {  
  141.             close(listenfd);  
  142.             do_service(connfd);  
  143.             exit(EXIT_SUCCESS);  
  144.         }  
  145.         if (pid > 0)  
  146.         {  
  147.             close(connfd);  
  148.         }  
  149.     }  
  150.     close(listenfd);  
  151. }  
客户端:
[cpp]  view plain  copy
  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. #define ERR_EXIT(m) do{perror(m);exit(EXIT_FAILURE);}while(1)  
  11. struct packet  
  12. {  
  13.     int len;  
  14.     char buf[1024];  
  15. };  
  16. ssize_t readn(int fd, void *buf, size_t count)  
  17. {  
  18.     size_t nleft = count;  
  19.     ssize_t nread;  
  20.     char *bufp = (char*)buf;  
  21.     while (nleft > 0)  
  22.     {  
  23.         if ((nread = read(fd, bufp, nleft)) < 0)  
  24.         {  
  25.             if (errno == EINTR)  
  26.             {  
  27.                 continue;  
  28.                 return -1;  
  29.             }  
  30.             else if (nread == 0)return count - nleft;  
  31.         }  
  32.         bufp = bufp + nread;  
  33.         nleft = nleft - nread;  
  34.     }  
  35.     return count;  
  36. }  
  37. ssize_t writen(int fd, void *buf, size_t count)  
  38. {  
  39.     size_t nleft = count;  
  40.     ssize_t nwrite;  
  41.     char *bufp = (char*)buf;  
  42.     while (nleft > 0)  
  43.     {  
  44.         if ((nwrite = write(fd, bufp, nleft)) < 0)  
  45.         {  
  46.             if (errno == EINTR)  
  47.             {  
  48.                 continue;  
  49.                 return -1;  
  50.             }  
  51.             else if (nwrite == 0)continue;  
  52.         }  
  53.         bufp = bufp + nwrite;  
  54.         nleft = nleft - nwrite;  
  55.     }  
  56.     return count;  
  57. }  
  58. ssize_t recv_peek(int sockfd, void *buf, size_t len)  
  59. {  
  60.     while (1)  
  61.     {  
  62.         int ret = recv(sockfd, buf, len, MSG_PEEK);  
  63.         if (ret == -1 && errno == EINTR)continue;  
  64.         return ret;  
  65.     }  
  66. }  
  67. ssize_t readline(int sockfd, void *buf, size_t maxline)  
  68. {  
  69.     int ret;  
  70.     int nread;  
  71.     char *bufp = (char*)buf;  
  72.     int nleft = maxline;  
  73.     while (1)  
  74.     {  
  75.         ret = recv_peek(sockfd, bufp, nleft);  
  76.         if (ret < 0)return ret;  
  77.         else if (ret == 0)return ret;//对方关闭了套接口  
  78.         nread = ret;  
  79.         for (int i = 0; i < nread; i++)  
  80.         {  
  81.             if (bufp[i] == '\n')  
  82.             {  
  83.                 ret = readn(sockfd, bufp, i + 1);//将缓冲区数据移除  
  84.                 if (ret != i + 1)exit(EXIT_FAILURE);  
  85.                 return ret;  
  86.             }  
  87.         }  
  88.         if (nread>nleft)exit(EXIT_FAILURE);//读到的数据不能超过缓冲区  
  89.         nleft -= nread;  
  90.         ret = readn(sockfd, bufp, nread);  
  91.         if (ret != nread)exit(EXIT_FAILURE);  
  92.         bufp += nread;  
  93.     }  
  94.     return -1;  
  95. }  
  96.   
  97. int main(void)  
  98. {  
  99.     int sockfd;  
  100.     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)ERR_EXIT("socket");  
  101.     struct sockaddr_in servaddr;  
  102.     memset(&servaddr, 0, sizeof(servaddr));  
  103.     servaddr.sin_family = AF_INET;  
  104.     servaddr.sin_port = htons(5188);  
  105.     servaddr.sin_addr.s_addr = inet_addr("127.0.1");  
  106.     if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)ERR_EXIT("bind");  
  107.     char sendbuf[1024];  
  108.     char recvbuf[1024];  
  109.     memset(sendbuf, 0, sizeof(sendbuf));  
  110.     memset(recvbuf, 0, sizeof(recvbuf));  
  111.     while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)  
  112.     {  
  113.         writen(sockfd, sendbuf, strlen(sendbuf));  
  114.         int ret = readline(sockfd, recvbuf, sizeof(recvbuf));  
  115.         if (ret == -1)ERR_EXIT("read");  
  116.         if (ret == 0)  
  117.         {  
  118.             printf("server close\n");  
  119.             break;  
  120.         }  
  121.         fputs(recvbuf, stdout);  
  122.         memset(sendbuf, 0, sizeof(sendbuf));  
  123.         memset(recvbuf, 0, sizeof(recvbuf));  
  124.     }  
  125.     close(sockfd);  
  126. }