TCP 粘包问题处理[2] ( the solution of sticky package problem of TCP )
2015-11-04 16:52
751 查看
Function :
In this passage , we offer another method to set out the sticky package. The method is that we encapsulate deadline function to realise to read by line. We set '\n' as the boundary of the message.
Server :
Client :
In this passage , we offer another method to set out the sticky package. The method is that we encapsulate deadline function to realise to read by line. We set '\n' as the boundary of the message.
Server :
/********************************************************************** > filename: echoserv2.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 the signed integer , size_t the unsigned integer ssize_t readn ( int fd , void *buf , size_t count ) //encapsulate like read function { size_t nleft = count ; ssize_t nread ; char *bufp ; bufp = ( char *) buf ; while ( nleft > 0 ) { //nread = read ( fd , bufp , nleft ) ; //printf ("nread = %d\n" , nread ) ; if ( (nread = read ( fd , bufp , nleft )) < 0 ) { if ( EINTR == errno ) // interrupted by the signal , we don't think this occasion is a mistake { continue ; } return -1 ; //failure } else if ( 0 == nread ) // peer close { 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 ( EINTR == errno ) { continue ; } return -1 ; } else if ( 0 == nwritten ) // like nothing happened to write function { continue ; } bufp += nwritten ; nleft -= nwritten ; } return count ; } ssize_t recv_peek ( int sockfd , void *buf , size_t len ) { while ( 1 ) { int ret = recv ( sockfd , buf , len , MSG_PEEK ) ; //only let buf read the data from sockfd but not remove the data from that sockfd(socket) //in comparison with read function it receive the data and remove the data in the socket if ( -1 == ret && EINTR == errno ) { continue ; //interrupted by signal } return ret ; } } ssize_t readline ( int sockfd , void *buf , size_t maxline ) { int ret ; int nread ; char *bufp ; bufp = (char*) buf ; int nleft ; nleft = maxline ; while (1 ) { ret = recv_peek ( sockfd, bufp , nleft ) ; if ( ret < 0 ) //failure { return ret ; } else if ( 0 == ret ) // peer closed { return ret ; } nread = ret ; int i ; for ( i = 0 ; i < nread ; i ++ ) { if ( '\n' == bufp[i]) { ret = readn (sockfd,bufp , i+1) ; if ( ret != i + 1 ) { exit(EXIT_FAILURE) ; } return ret ; } } if ( nread > nleft ) // the data that we read(nread) can't be more than the real data in the socket { exit ( EXIT_FAILURE ) ; } nleft -= nread ; ret = readn ( sockfd , bufp , nread ) ; // read n characters from the socket ( don't contain '\n') if ( ret != nread ) { exit(EXIT_FAILURE ) ; } bufp += nread ; } return -1 ; } void do_service ( int conn ) { char recvbuf[1024] ; while(1) { memset ( recvbuf , 0 , sizeof(recvbuf) ) ; int ret = readline ( conn , recvbuf , sizeof(recvbuf) ) ; if ( -1 == ret ) { ERR_EXIT("readline") ; } if ( 0 == ret ) { // ERR_EXIT ("client close\n") ; printf("client close\n") ; break ; } fputs ( recvbuf , stdout ) ; writen ( conn , recvbuf , strlen(recvbuf) ) ; } } 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 bind has already used by SO_REUSEADDR int on = 1 ; int opt ; if (( opt = setsockopt (listenfd ,SOL_SOCKET , SO_REUSEADDR, &on , sizeof(on) )) < 0 ) { ERR_EXIT("setsocketopt") ; } 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) ) ; int pid ; pid = fork() ; // creat the child process to set out the multi-connection from clients if ( -1 == pid ) { ERR_EXIT ("fork") ; } if ( 0 == pid ) { close (listenfd) ; // the son's pid didn't need to process the listen , so we close listenfd ; do_service (conn) ; exit(EXIT_SUCCESS) ; } else { close (conn) ; // the father's pid didn't need to process the acceept ,so we 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 ) { // 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 ; } ssize_t recv_peek ( int sockfd , void *buf , size_t len ) { while ( 1 ) { int ret = recv ( sockfd , buf , len , MSG_PEEK ) ; //only let buf read the data from sockfd but not remove the data from that sockfd(socket) //in comparison with read function it receive the data and remove the data in the socket if ( -1 == ret && EINTR == errno ) { continue ; //interrupted by signal } return ret ; } } ssize_t readline ( int sockfd , void *buf , size_t maxline ) { int ret ; int nread ; char *bufp ; bufp = (char*) buf ; int nleft ; nleft = maxline ; while (1 ) { ret = recv_peek ( sockfd, bufp , nleft ) ; if ( ret < 0 ) //failure { return ret ; } else if ( 0 == ret ) // peer closed { return ret ; } nread = ret ; int i ; for ( i = 0 ; i < nread ; i ++ ) { if ( '\n' == bufp[i]) { ret = readn (sockfd,bufp , i+1) ; if ( ret != i + 1 ) { exit(EXIT_FAILURE) ; } return ret ; } } if ( nread > nleft ) // the data that we read(nread) can't be more than the real data in the socket { exit ( EXIT_FAILURE ) ; } nleft -= nread ; ret = readn ( sockfd , bufp , nread ) ; // read n characters from the socket ( don't contain '\n') if ( ret != nread ) { exit(EXIT_FAILURE ) ; } bufp += nread ; } return -1 ; } 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} ; memset ( sendbuf , 0 , sizeof(sendbuf) ) ; memset ( recvbuf , 0 , sizeof(recvbuf) ) ; int n ; while( fgets ( sendbuf , sizeof(sendbuf) , stdin ) != NULL ) { //fgets get the data with '\n' in default writen ( sock , sendbuf ,strlen(sendbuf) ) ; // the former 4 bytes and the real data(n) int ret = readline ( sock , recvbuf , sizeof(recvbuf) ) ; if ( -1 == ret ) { ERR_EXIT ("readline") ; } else if ( 0 == ret ) //may interrupted by signal { printf ("clien________ close\n") ; break ; } fputs ( recvbuf , stdout ) ; memset ( sendbuf , 0 , sizeof(sendbuf) ) ; memset ( recvbuf , 0 , sizeof(recvbuf) ) ; } close ( sock ) ; return 0 ; }
相关文章推荐
- Android开发中,使用https发送安全请求的实现
- 计算机网络之网络层
- HTTPClient
- C++网络编程 如何使用SOCKET 发送HTTP1.1 GET POST请求包
- java网络编程(一):java传统的阻塞IO以及多线程解决方案
- Yum安装httpd的问题
- RedHat 5 httpd mod_ssl 报错
- 无法启动httpd服务
- 网络知识补遗
- c http报文头字段内容解析小函数
- android网络请求框架 HttpClient与Volley的性能对比
- 黑马程序员——Java基础——网络编程1
- 写给自己的网络请求解析 返回数组和字典类型不同的处理方法
- 多媒体开发之rtcp详解---rtcp数据包
- asp.net 百度编辑器 UEditor 上传图片 图片上传配置 编辑器配置 网络连接错误,请检查配置后重试
- COGS【831】最短网络
- php curl http https
- 基于流模式的字节byte缓存区 bytebuffer.cs 用于tcp/udp的网络数据高效处理
- ASIHTTPRequest使用
- [环境搭建]-Web Api搭建到IIS服务器后PUT请求返回HTTP Error 405.0 - Method Not Allowed 解决方法 转摘:http://blog.csdn.net/qiujuer/article/details/23827531