socket编程中的粘包问题解决方案
1.自定义传输,数据结构。struct packet.
服务器端:
1 #include <unistd.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <sys/socket.h> 5 #include <sys/types.h> 6 #include <errno.h> 7 #include <arpa/inet.h> 8 #include <netinet/in.h> 9 #include <string.h> 10 11 12 // allow multi client to connect . 13 14 #define ERR_EXIT(m) \ 15 do { \ 16 perror(m); \ 17 exit(EXIT_FAILURE); \ 18 } while(0) 19 20 struct packet 21 { 22 int len; 23 char buf[1024]; 24 }; 25 26 ssize_t readn(int fd, void* buf, size_t count) 27 { 28 size_t nleft = count; 29 size_t nread; 30 char *pbuf = (char*)buf; 31 32 printf("nread\n"); 33 while(nleft > 0) 34 { 35 printf("nleft:%d\n", nleft); 36 if((nread = read(fd, pbuf, nleft)) < 0) 37 { 38 39 if(errno == EINTR) 40 continue; 41 42 return -1; 43 } 44 else if (nread == 0) 45 return count - nleft; 46 47 printf("nread:%d\n", nread); 48 49 pbuf += nread; 50 nleft -= nread; 51 } 52 53 return count; 54 } 55 56 ssize_t writen(int fd, const void *buf, size_t count) 57 { 58 59 size_t nleft = count; 60 size_t nwriten; 61 char *pbuf = (char*)buf; 62 63 while(nleft > 0) 64 { 65 if((nwriten = write(fd, pbuf, nleft)) < 0) 66 { 67 if(errno == EINTR) 68 continue; 69 70 return -1; 71 } 72 else if (nwriten == 0) 73 continue; 74 75 pbuf += nwriten; 76 nleft -= nwriten; 77 } 78 79 return count; 80 81 } 82 83 void do_service(int connfd) 84 { 85 //char recvbuf[1024]; 86 struct packet recvbuf; 87 int n; 88 while(1) 89 { 90 memset(&recvbuf, 0, sizeof(recvbuf)); 91 int ret = readn(connfd, &recvbuf.len, 4); // 4 = sizeof(sendbuf.len) 92 93 if(ret == -1) 94 { 95 ERR_EXIT("read error!\n"); 96 } 97 else if(ret == 4) // 98 { 99 printf("client close\n"); 100 break; 101 } 102 103 n = ntohl(recvbuf.len);//convert network order to host 104 ret = readn(connfd, &recvbuf.buf, n); // 4 = sizeof(sendbuf.len) 105 106 if(ret == -1) 107 { 108 ERR_EXIT("read error!\n"); 109 } 110 else if(ret == 4) // 111 { 112 printf("client close\n"); 113 break; 114 } 115 fputs(recvbuf.buf, stdout); 116 writen(connfd, &recvbuf, 4+n); 117 } 118 close(connfd); 119 } 120 121 int main(int argc, char* argv[]) 122 { 123 int listenfd ; 124 if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 125 { 126 ERR_EXIT("socket"); 127 } 128 129 struct sockaddr_in servaddr; 130 memset(&servaddr, 0, sizeof(servaddr)); 131 servaddr.sin_family = AF_INET; 132 servaddr.sin_port = htons(5188); 133 servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 134 // servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 135 // inet_aton("127.0.0.1", &servaddr.sin_addr); 136 137 // add begin 138 int on = 1;//open TIME_WAIT status allow the server to restart 139 if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 140 { 141 ERR_EXIT("setsockopt"); 142 } 143 // add end 144 145 if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) 146 { 147 ERR_EXIT("bind"); 148 } 149 150 if(listen(listenfd, SOMAXCONN) < 0) 151 { 152 ERR_EXIT("listen"); 153 } 154 155 struct sockaddr_in peeraddr; 156 socklen_t peerlen = sizeof(peeraddr); 157 158 int connfd ; 159 160 161 pid_t pid; 162 163 while(1) 164 { 165 if((connfd = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0) 166 { 167 ERR_EXIT("accept"); 168 } 169 170 printf("IP:%s, Port:%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port)); 171 172 pid = fork(); 173 if(pid == -1) 174 ERR_EXIT("fork"); 175 176 if(pid == 0) // child process 177 { 178 179 close(listenfd); 180 do_service(connfd); 181 exit(EXIT_SUCCESS);//while client close, processor need be exited 182 } 183 else // accept 184 { 185 close(connfd); // needn't deal connfd 186 } 187 } 188 189 return 0; 190 }
客户端:
1 #include <unistd.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <errno.h> 5 #include <string.h> 6 7 #include <sys/socket.h> 8 #include <arpa/inet.h> 9 #include <sys/types.h> 10 #include <netinet/in.h> 11 12 #define ERR_EXIT(m) \ 13 do { \ 14 perror(m); \ 15 exit(EXIT_FAILURE); \ 16 } while(0) 17 18 struct packet 19 { 20 int len; 21 char buf[1024]; 22 }; 23 24 ssize_t readn(int fd, void* buf, size_t count) 25 { 26 size_t nleft = count; 27 size_t nread; 28 char *pbuf = (char*)buf; 29 30 while(nleft > 0) 31 { 32 if((nread = read(fd, pbuf, nleft)) < 0) 33 { 34 if(errno == EINTR) 35 continue; 36 37 return -1; 38 } 39 else if (nread == 0) 40 return count - nleft; 41 42 pbuf += nread; 43 nleft -= nread; 44 } 45 46 return count; 47 } 48 49 ssize_t writen(int fd, const void *buf, size_t count) 50 { 51 52 size_t nleft = count; 53 size_t nwriten; 54 char *pbuf = (char*)buf; 55 56 while(nleft > 0) 57 { 58 if((nwriten = write(fd, pbuf, nleft)) < 0) 59 { 60 if(errno == EINTR) 61 continue; 62 63 return -1; 64 } 65 else if (nwriten == 0) 66 continue; 67 68 pbuf += nwriten; 69 nleft -= nwriten; 70 } 71 72 return count; 73 74 } 75 76 int main(int argc, char* argv[]) 77 { 78 int sockfd; 79 if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 80 { 81 ERR_EXIT("socket"); 82 } 83 84 struct sockaddr_in addr; 85 addr.sin_family = AF_INET; 86 addr.sin_port = htons(5188); 87 addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 88 89 if(connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) 90 { 91 ERR_EXIT("connect"); 92 } 93 94 struct packet sendbuf; 95 struct packet recvbuf; 96 memset(&sendbuf, 0, sizeof(sendbuf)); 97 memset(&recvbuf, 0, sizeof(recvbuf)); 98 99 int n; 100 while(fgets(&sendbuf.buf, sizeof(sendbuf.len), stdin) != NULL) 101 { 102 n = strlen(sendbuf.buf); 103 sendbuf.len = htonl(n);//convert the data to network order 104 writen(sockfd, &sendbuf, 4 + n);// n represents sizeof(sendbuf.len); 105 106 int ret = readn(sockfd, &recvbuf.len, 4); // 4 = sizeof(sendbuf.len) 107 108 if(ret == -1) 109 { 110 ERR_EXIT("read error!\n"); 111 } 112 else if(ret == 4) // 113 { 114 printf("client close\n"); 115 break; 116 } 117 118 n = ntohl(sendbuf.len);//convert network order to host 119 ret = readn(sockfd, &recvbuf.buf, n); // 4 = sizeof(sendbuf.len) 120 121 if(ret == -1) 122 { 123 ERR_EXIT("read error!\n"); 124 } 125 else if(ret == 4) // 126 { 127 printf("client close\n"); 128 break; 129 } 130 fputs(recvbuf.buf, stdout); 131 memset(&recvbuf, 0, sizeof(recvbuf)); 132 memset(&sendbuf, 0, sizeof(sendbuf)); 133 } 134 135 close(sockfd); 136 return 0; 137 }
自定数据包在socket编程中传递。