TCP 粘包问题处理[1] ( the solution of sticky package problem of TCP )
2015-11-04 00:49
555 查看
Because TCP is a stream protocol, so in the translation , there may have lots of sticky bags.
The passage offer two method to solve this problem.
1.We use the fixed length package to solve it.
2. We designed the protocol by ourselves , a struct wiht the head and body of the package. When we receive the message the need to receive the head of the message and then get the body of the package.
For the first solution:
Server:
Client :
The second solution :
Server :
Client :
The passage offer two method to solve this problem.
1.We use the fixed length package to solve it.
2. We designed the protocol by ourselves , a struct wiht the head and body of the package. When we receive the message the need to receive the head of the message and then get the body of the package.
For the first solution:
Server:
/************************************************************************ > file name: echoserv.c > Author: ma6174 > Mail: ma6174@163.com > Created Time: Thu 29 Oct 16:38:57 2015 ************************************************************************/ #include <stdio.h> #include <sys/socket.h> #include <string.h> #include <arpa/inet.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #define ERR_EXIT(m) \ do \ {\ perror(m) ;\ exit(EXIT_FAILURE) ;\ }while(0) //ssize_t signed integer size_t unsigned integer ssize_t readn ( int fd , void *buf , size_t count ) // encapsulate readn as the function of read { size_t nleft = count ; ssize_t nread ; char *bufp ; bufp = ( char *) buf ; while ( nleft > 0 ) { nread = read ( fd , bufp , nleft ) ; if( nread < 0 ) { if ( errno == EINTR ) // interrupted by signal , we don't think this occasion is not right { continue ; } return -1 ; } else if ( 0 == nread ) //peer closed { return count - nleft ; } bufp += nread ; nleft -= nread ; } return count ; } ssize_t writen ( int fd , const void *buf ,size_t count ) { size_t nleft = count ; ssize_t nwritten ; char *bufp ; bufp = ( char * ) buf ; while ( nleft > 0 ) { if ( ( nwritten = write ( fd , bufp , nleft ) ) < 0 ) { if ( errno == EINTR ) // just like the occasion in writen { continue ; } return -1 ; } else if ( 0 == nwritten ) // if 0 == nread , like nothing happened to write ... { continue ; } bufp += nwritten ; nleft -= nwritten ; } return count ; } void do_service ( int conn ) { char recvbuf[1024] ; while(1) { memset ( recvbuf , 0 , sizeof(recvbuf)) ; int ret = readn( conn , recvbuf , sizeof(recvbuf) ) ; printf ("ret = %d\n" , ret ) ; if ( 0 == ret ) { printf ("client close") ; break ; } else if ( -1 == ret ) { ERR_EXIT ("read") ; } fputs ( recvbuf , stdout ) ; writen ( conn , recvbuf , ret ) ; } } int main () { int listenfd ; if (( listenfd = socket ( PF_INET , SOCK_STREAM , IPPROTO_TCP )) < 0 ) { ERR_EXIT("socket") ; } struct sockaddr_in servaddr ; memset ( & servaddr , 0 , sizeof(servaddr ) ) ; servaddr.sin_family = AF_INET ; servaddr.sin_port = htons (5188) ; servaddr.sin_addr.s_addr = htonl(INADDR_ANY) ; //INTADDR_ANY == 0 //other two means to change the host address to network address //servaddr.sin_addr.s_addr = inet_addr("127.0.0.1") ; //inet_aton("127.0.0.1" , &servaddr.sin_addr) ; /* set out the problem that the address has already been used by SO_REUSEADDR int on = 1 ; int opt ; if (( opt = setsockopt (listenfd ,SOL_SOCKET , SO_REUSEADDR, &on , sizeof(on) )) < 0 ) { ERR_EXIT("setsocketopt") ; } */ int on = 1 ; if ( setsockopt ( listenfd , SOL_SOCKET , SO_REUSEADDR , &on , sizeof(on) ) < 0 ) { ERR_EXIT("setsockopt") ; } if ( bind ( listenfd , (struct sockaddr * ) &servaddr , sizeof(servaddr )) < 0 ) { ERR_EXIT("bind") ; } if ( listen ( listenfd , SOMAXCONN) < 0 ) { ERR_EXIT("listen") ; } struct sockaddr_in peeraddr ; socklen_t peerlen = sizeof(peeraddr) ; int conn ; while ( 1 ) { if ( (conn = accept ( listenfd , ( struct sockaddr * )&peeraddr , &peerlen )) < 0 ) { ERR_EXIT("accept") ; } // print the client's address and ip ' printf ("ip = %s port = %d\n", inet_ntoa(peeraddr.sin_addr) ,ntohs(peeraddr.sin_port) ) ; pid_t pid ; pid = fork() ; if ( -1 == pid ) { ERR_EXIT("fork") ; } if ( 0 == pid ) { close(listenfd) ; do_service(conn) ; exit (EXIT_SUCCESS ) ; } else { close(conn) ; } } return 0 ; }
Client :
/************************************************************************ >file name : echocli.c > Author: ma6174 > Mail: ma6174@163.com > Created Time: Thu 29 Oct 16:38:57 2015 ************************************************************************/ #include <stdio.h> #include <sys/socket.h> #include <string.h> #include <arpa/inet.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #define ERR_EXIT(m) \ do \ {\ perror(m) ;\ exit(EXIT_FAILURE) ;\ }while(0) //ssize_t signed integer size_t unsigned integer ssize_t readn ( int fd , void *buf , size_t count ) // encapsulate readn as the function of read { size_t nleft = count ; ssize_t nread ; char *bufp ; bufp = ( char *) buf ; // printf ("nleft = %d\n" , nleft ) ; while ( nleft > 0 ) { nread = read ( fd , bufp , nleft ) ; if( nread < 0 ) { if ( errno == EINTR ) // interrupted by signal , we don't think this occasion is not right { continue ; } return -1 ; } else if ( 0 == nread ) //peer closed { return count - nleft ; //break ; } // printf ("nreaad = %d\n" , nread ) ; bufp += nread ; nleft -= nread ; } return count ; } ssize_t writen ( int fd , const void *buf ,size_t count ) { size_t nleft = count ; ssize_t nwritten ; char *bufp ; bufp = ( char * ) buf ; while ( nleft > 0 ) { if ( ( nwritten = write ( fd , bufp , nleft ) ) < 0 ) { if ( errno == EINTR ) // just like the occasion in writen { continue ; } return -1 ; } else if ( 0 == nwritten ) // if 0 == nread , like nothing happened to write ... { continue ; } bufp += nwritten ; nleft -= nwritten ; } return count ; } int main () { int sock ; if (( sock= socket ( PF_INET , SOCK_STREAM , IPPROTO_TCP )) < 0 ) { ERR_EXIT("socket") ; } struct sockaddr_in servaddr ; memset ( & servaddr , 0 , sizeof(servaddr) ) ; servaddr.sin_family = AF_INET ; servaddr.sin_port = htons (5188) ; //servaddr.sin_addr.s_addr = htonl(INADDR_ANY) ; servaddr.sin_addr.s_addr = inet_addr("127.0.0.1") ; //inet_aton("127.0.0.1" , &servaddr.sin_addr) ; if ( connect ( sock , ( struct sockaddr * )& servaddr, sizeof(servaddr )) < 0 ) { ERR_EXIT("connet") ; } char sendbuf[1024] = {0} ; char recvbuf[1024] = {0} ; while( fgets ( sendbuf , sizeof(sendbuf) , stdin ) != NULL ) { writen ( sock , sendbuf , sizeof(sendbuf) ) ; readn ( sock , recvbuf , sizeof(recvbuf ) ) ; fputs ( recvbuf , stdout ) ; memset ( sendbuf , 0 , sizeof(sendbuf) ) ; memset ( recvbuf , 0 , sizeof(recvbuf) ) ; } close ( sock ) ; return 0 ; }
The second solution :
Server :
/************************************************************************ > file name: echoserv.c > Author: ma6174 > Mail: ma6174@163.com > Created Time: Thu 29 Oct 16:38:57 2015 ************************************************************************/ #include <stdio.h> #include <sys/socket.h> #include <string.h> #include <arpa/inet.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #define ERR_EXIT(m) \ do \ {\ perror(m) ;\ exit(EXIT_FAILURE) ;\ }while(0) struct packet { int len ; // head of the package char buf[1024] ; // store the real data , the body of the package }; //ssize_t signed integer size_t unsigned integer ssize_t readn ( int fd , void *buf , size_t count ) // encapsulate readn as the function of read { size_t nleft = count ; ssize_t nread ; char *bufp ; bufp = ( char *) buf ; while ( nleft > 0 ) { nread = read ( fd , bufp , nleft ) ; if( nread < 0 ) { if ( errno == EINTR ) // interrupted by signal , we don't think this occasion is not right { continue ; } return -1 ; } else if ( 0 == nread ) //peer closed { return count - nleft ; } bufp += nread ; nleft -= nread ; } return count ; } ssize_t writen ( int fd , const void *buf ,size_t count ) { size_t nleft = count ; ssize_t nwritten ; char *bufp ; bufp = ( char * ) buf ; while ( nleft > 0 ) { if ( ( nwritten = write ( fd , bufp , nleft ) ) < 0 ) { if ( errno == EINTR ) // just like the occasion in writen { continue ; } return -1 ; } else if ( 0 == nwritten ) // if 0 == nread , like nothing happened to write ... { continue ; } bufp += nwritten ; nleft -= nwritten ; } return count ; } void do_service ( int conn ) { struct packet recvbuf ; while(1) { memset ( &recvbuf , 0 , sizeof(recvbuf)) ; int ret = readn( conn , &recvbuf.len , 4 ) ; //receive the 4 bytes at first if ( -1 == ret ) { ERR_EXIT ("read") ; } else if ( ret < 4 ) //may interrupted by signal { printf ("clien close\n") ; break ; } int n ; n = ntohl(recvbuf.len); //receive the length of the data ret = readn ( conn , recvbuf.buf , n ) ; if ( -1 == ret ) { ERR_EXIT("read") ; } else if ( ret < n ) { printf ("client close\n") ; break ; } fputs ( recvbuf.buf , stdout ) ; writen ( conn , &recvbuf , 4+n ) ; } } int main () { int listenfd ; if (( listenfd = socket ( PF_INET , SOCK_STREAM , IPPROTO_TCP )) < 0 ) { ERR_EXIT("socket") ; } struct sockaddr_in servaddr ; memset ( & servaddr , 0 , sizeof(servaddr ) ) ; servaddr.sin_family = AF_INET ; servaddr.sin_port = htons (5188) ; servaddr.sin_addr.s_addr = htonl(INADDR_ANY) ; //INTADDR_ANY == 0 //other two means to change the host address to network address //servaddr.sin_addr.s_addr = inet_addr("127.0.0.1") ; //inet_aton("127.0.0.1" , &servaddr.sin_addr) ; /* set out the problem that the address has already been used by SO_REUSEADDR int on = 1 ; int opt ; if (( opt = setsockopt (listenfd ,SOL_SOCKET , SO_REUSEADDR, &on , sizeof(on) )) < 0 ) { ERR_EXIT("setsocketopt") ; } */ int on = 1 ; if ( setsockopt ( listenfd , SOL_SOCKET , SO_REUSEADDR , &on , sizeof(on) ) < 0 ) { ERR_EXIT("setsockopt") ; } if ( bind ( listenfd , (struct sockaddr * ) &servaddr , sizeof(servaddr )) < 0 ) { ERR_EXIT("bind") ; } if ( listen ( listenfd , SOMAXCONN) < 0 ) { ERR_EXIT("listen") ; } struct sockaddr_in peeraddr ; socklen_t peerlen = sizeof(peeraddr) ; int conn ; while ( 1 ) { if ( (conn = accept ( listenfd , ( struct sockaddr * )&peeraddr , &peerlen )) < 0 ) { ERR_EXIT("accept") ; } // print the client's address and ip ' printf ("ip = %s port = %d\n", inet_ntoa(peeraddr.sin_addr) ,ntohs(peeraddr.sin_port) ) ; pid_t pid ; pid = fork() ; if ( -1 == pid ) { ERR_EXIT("fork") ; } if ( 0 == pid ) { close(listenfd) ; do_service(conn) ; exit (EXIT_SUCCESS ) ; } else { close(conn) ; } } return 0 ; }
Client :
/************************************************************************ >file name : echocli.c > Author: ma6174 > Mail: ma6174@163.com > Created Time: Thu 29 Oct 16:38:57 2015 ************************************************************************/ #include <stdio.h> #include <sys/socket.h> #include <string.h> #include <arpa/inet.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #define ERR_EXIT(m) \ do \ {\ perror(m) ;\ exit(EXIT_FAILURE) ;\ }while(0) struct packet { int len ; // the haad of the package char buf[1024] ; // store the real data , the body of the package }; //ssize_t signed integer size_t unsigned integer ssize_t readn ( int fd , void *buf , size_t count ) // encapsulate readn as the function of read { size_t nleft = count ; ssize_t nread ; char *bufp ; bufp = ( char *) buf ; // printf ("nleft = %d\n" , nleft ) ; while ( nleft > 0 ) { // printf ("nleft = %d\n" , nleft ) ; nread = read ( fd , bufp , nleft ) ; // printf ("nread = %d\n" , nread ) ; if( nread < 0 ) { if ( errno == EINTR ) // interrupted by signal , we don't think this occasion is not right { continue ; } return -1 ; } else if ( 0 == nread ) //peer closed { return count - nleft ; //break ; } // printf ("nreaad = %d\n" , nread ) ; bufp += nread ; nleft -= nread ; } return count ; } ssize_t writen ( int fd , const void *buf ,size_t count ) { size_t nleft = count ; ssize_t nwritten ; char *bufp ; bufp = ( char * ) buf ; while ( nleft > 0 ) { if ( ( nwritten = write ( fd , bufp , nleft ) ) < 0 ) { if ( errno == EINTR ) // just like the occasion in writen { continue ; } return -1 ; } else if ( 0 == nwritten ) // if 0 == nread , like nothing happened to write ... { continue ; } bufp += nwritten ; nleft -= nwritten ; } return count ; } int main () { int sock ; if (( sock= socket ( PF_INET , SOCK_STREAM , IPPROTO_TCP )) < 0 ) { ERR_EXIT("socket") ; } struct sockaddr_in servaddr ; memset ( & servaddr , 0 , sizeof(servaddr) ) ; servaddr.sin_family = AF_INET ; servaddr.sin_port = htons (5188) ; //servaddr.sin_addr.s_addr = htonl(INADDR_ANY) ; servaddr.sin_addr.s_addr = inet_addr("127.0.0.1") ; //inet_aton("127.0.0.1" , &servaddr.sin_addr) ; if ( connect ( sock , ( struct sockaddr * )& servaddr, sizeof(servaddr )) < 0 ) { ERR_EXIT("connet") ; } struct packet sendbuf ; struct packet recvbuf ; memset ( &sendbuf , 0 , sizeof(sendbuf) ) ; memset ( &recvbuf , 0 , sizeof(recvbuf) ) ; int n ; while( fgets ( sendbuf.buf , sizeof(sendbuf.buf) , stdin ) != NULL ) { n = strlen ( sendbuf.buf) ; // n == the length of that package sendbuf.len = htonl(n) ; // change host byte order to network byte order writen ( sock , &sendbuf , 4+n ) ; // the former 4 bytes and the real data(n) int ret = readn( sock , &recvbuf.len , 4 ) ; //receive the 4 bytes at first //printf ("ret = %d\n" , ret ) ; if ( -1 == ret ) { ERR_EXIT ("read") ; break ; } else if ( ret < 4 ) //may interrupted by signal { printf ("clien close\n") ; break ; } int n ; n = ntohl(recvbuf.len) ; //receive the length of the data ret = readn ( sock , recvbuf.buf , n ) ; if ( -1 == ret ) { ERR_EXIT("read") ; } else if ( ret < n ) { printf ("client close\n") ; break ; } fputs ( recvbuf.buf , stdout ) ; memset ( &sendbuf , 0 , sizeof(sendbuf) ) ; memset ( &recvbuf , 0 , sizeof(recvbuf) ) ; } close ( sock ) ; return 0 ; }
相关文章推荐
- nginx或httpd实现反向代理tomcat并实现会话保持(二)
- Servlet之HttpSession验证码
- https原理及tomcat配置https方法
- 网络配置
- android:java.lang.NoClassDefFoundError: com.lidroid.xutils.HttpUtils 异常的解决
- 2015/11/3 完成酷欧天气的数据库、网络连接类的编写
- 初学linux_centos7网络配置
- 创建XMLHttpRequest对象
- XMPP框架 微信项目开发之网络通信基础——OSI_TCP/IP 参考模型的理解
- 网络通信中字节序转换问题
- UDP client,UDP server, TCP server, TCP client
- Android - 使用Volley请求网络数据
- iOS—OC——TCP/UDP HTTP
- 利用domain access建立子站点网络
- ASP.NET WebAPI 08 Message,HttpConfiguration,DependencyResolver
- 【网络】IP地址
- 调试代码的方法--将网络获取到的数据存储到文件中,然后打开文件看结果。
- TCP/IP协议
- 初识TCP:传输控制协议
- 解决虚拟机vmware中REDHAT不能上网问题。