Article directory
Flow protocol and packet sticking
- TCP is a transport service based on byte stream. It has no boundary and can not guarantee how many bytes can be returned by peers at a time, so it is easy to generate sticky packets
- UDP transmits datagram with boundary
Sticky bag
- Causes
- SQ ﹣ sndbuf socket has buffer (send buffer, receive buffer)
- Maximum value of network data transmitted by tcp MSS size limit
- The link layer also has the MTU (maximum transmission unit) size limit. If the data packet is larger than the maximum transmission unit, it needs to be fragmented in the IP layer, resulting in message segmentation
- Traffic control and congestion control of tcp
- Tardiness mechanism of tacp
Conclusion: TCP/IP protocol does not deal with packet sticking in the transport layer, which must be handled by the programmer
- Treatment plan
- Essentially, the boundary between message and message should be maintained in the application layer
- Fixed length package
- End of package add (FTP)
- Head plus length
- More complex application layer protocol
readn writen
- readn
ssize_t readn(int fd, void *buf, size_t count) { size_t nleft = count; ssize_t nread; char *bufp = (char*)buf; while(nleft > 0) { if((nread = read(fd, bufp, nleft)) < 0) { if(errno == EINTR) continue; return -1; } else if(nread == 0) return count - nleft; bufp += nread; nleft -= nread; } return count; }
- writen
ssize_t writen(int fd, const void *buf, size_t count) { size_t nleft = count; ssize_t nwritten; char *bufp = (char*)buf; while(nleft > 0) { if((nwritten = write(fd, bufp, nleft)) < 0) { if(errno == EINTR) continue; return -1; } else if(nwritten == 0) continue; bufp += nwritten; nleft -= nwritten; } return count; }
Client sends fixed length package code
Note: increased burden
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <unistd.h> #include <netinet/in.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ }while(0) ssize_t readn(int fd, void *buf, size_t count) { size_t nleft = count; ssize_t nread; char *bufp = (char*)buf; while(nleft > 0) { if((nread = read(fd, bufp, nleft)) < 0) { if(errno == EINTR) continue; return -1; } else if(nread == 0) 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 = (char*)buf; while(nleft > 0) { if((nwritten = write(fd, bufp, nleft)) < 0) { if(errno == EINTR) continue; return -1; } else if(nwritten == 0) continue; bufp += nwritten; nleft -= nwritten; } return count; } int main(void) { int sock;//Create a socket similar to the file descriptor. if((sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0) {//Create socket, success return socket, failure return - 1 ERR_EXIT("socket"); } //Address initialization struct sockaddr_in servaddr;//Define IPV4 socket address memset(&servaddr,0,sizeof(servaddr));//Initialization address servaddr.sin_family = AF_INET; //Define address family servaddr.sin_port = htons(5188);//Define port number //Servaddr. Sin? Addr. S? Addr = htonl (intaddr? Any); / / define the IP address intaddr? Any, which means all the addresses of the machine //Second method (recommended) servaddr.sin_addr.s_addr = inet_addr("10.18.95.28");//Define IP address //The third way //inet_aton("10.18.95.29",&servaddr.sin_addr); if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)//Connection function { ERR_EXIT("connect"); } char sendbuf[1024] = {0}; char recvbuf[1024] = {0}; while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL)//Communication details { 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; }
Echo client / server
echosrv.c
#include<unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <signal.h>//Signal, interprocess communication #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #define ERR_EXIT(m) \ do\ {\ perror(m);\ exit(EXIT_FAILURE);\ }while (0) struct packet { int len; char buf[1024]; }; ssize_t readn(int fd, void *buf, size_t count) { size_t nleft = count; ssize_t nread; char *bufp = (char*)buf; while(nleft > 0) { if((nread = read(fd, bufp, nleft)) < 0) { if(errno == EINTR) continue; return -1; } else if(nread == 0) 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 = (char*)buf; while(nleft > 0) { if((nwritten = write(fd, bufp, nleft)) < 0) { if(errno == EINTR) continue; return -1; } else if(nwritten == 0) continue; bufp += nwritten; nleft -= nwritten; } return count; } void do_service(int conn) { struct packet recvbuf; int n; while(1) { memset(&recvbuf, 0,sizeof(recvbuf)); int ret = readn(conn, &recvbuf.len, 4); if(ret == -1) ERR_EXIT("read"); else if(ret < 4) { printf("client_close\n"); break; } n = ntohl(recvbuf.len); ret = readn(conn, recvbuf.buf, n); if(ret == -1) ERR_EXIT("read"); else if(ret < n) { printf("client_close\n"); break; } fputs(recvbuf.buf, stdout); writen(conn, &recvbuf, 4+n); } } int main(void) { int listenfd;//Passive socket if((listenfd = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0)//Failed to create socket less than 0 /* if((listenfd = socket(PF_INET,SOCK_STREAM,0))<0);*///Let kernel choose protocol by itself 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);//Represents any address of the machine /*servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");*/ /*inet_aton("127.0.0.1",&servaddr.sin_addr);*/ int on = 1;//Enable address reuse 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)//Becomes a passive socket after listening ERR_EXIT("listen"); struct sockaddr_in peeraddr; socklen_t peerlen = sizeof(peeraddr); int conn;//Active socket if((conn = accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen))<0) ERR_EXIT("accept"); pid_t pid;//The parent process is used to get data, and the child process is used to send data while(1) { if((conn = accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen)) < 0) ERR_EXIT("accept"); printf("ip=%s,port=%d\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port)); pid = fork(); if(pid == -1) ERR_EXIT("fork"); if(pid == 0) { close(listenfd); do_service(conn); exit(EXIT_SUCCESS); } else close(conn); } return 0; }
echocli.c
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <unistd.h> #include <netinet/in.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ }while(0) struct packet { int len; char buf[1024]; }; ssize_t readn(int fd, void *buf, size_t count) { size_t nleft = count; ssize_t nread; char *bufp = (char*)buf; while(nleft > 0) { if((nread = read(fd, bufp, nleft)) < 0) { if(errno == EINTR) continue; return -1; } else if(nread == 0) 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 = (char*)buf; while(nleft > 0) { if((nwritten = write(fd, bufp, nleft)) < 0) { if(errno == EINTR) continue; return -1; } else if(nwritten == 0) continue; bufp += nwritten; nleft -= nwritten; } return count; } int main(void) { int sock;//Create a socket similar to the file descriptor. if((sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0) {//Create socket, success return socket, failure return - 1 ERR_EXIT("socket"); } //Address initialization struct sockaddr_in servaddr;//Define IPV4 socket address memset(&servaddr,0,sizeof(servaddr));//Initialization address servaddr.sin_family = AF_INET; //Define address family servaddr.sin_port = htons(5188);//Define port number //Servaddr. Sin? Addr. S? Addr = htonl (intaddr? Any); / / define the IP address intaddr? Any, which means all the addresses of the machine //Second method (recommended) servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");//Define IP address //The third way //inet_aton("10.18.95.29",&servaddr.sin_addr); if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)//Connection function { ERR_EXIT("connect"); } 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)//Communication details { n = strlen(sendbuf.buf); sendbuf.len = htonl(n); writen(sock, &sendbuf, 4+n); int ret = readn(sock, &recvbuf.len, 4); if(ret == -1) ERR_EXIT("read"); else if(ret < 4) { printf("client_close\n"); break; } n = ntohl(recvbuf.len); ret = readn(sock, recvbuf.buf, n); if(ret == -1) 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; }
Reference material
- https://www.cnblogs.com/zhanggaofeng/p/6134757.html