- 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 }
-
- 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 }
-
- service