streaming protocols and sticky packets
The performance of a sticky bag
Host A sends data to host B; The way host B receives data is not deterministic
The reason for the sticky bag production
Description
Tcp |
Byte stream, no border |
Peer, one-time read operation, can not guarantee to completely read the message |
Udp |
Datagram, with border |
The number of packets received by the other party is indeterminate. |
The cause analysis of the problem of producing sticky bag
1.SQ_SNDBUF socket itself has buffer (send buffer, accept buffer)
2,TCP transmission of the end of the MSS size limit
3, link layer also has the MTU size limit , if the packet is larger than >MTU to be fragmented at the IP layer, resulting in message segmentation.
4, TCP traffic control and congestion control, may also lead to adhesive packets
5, TCP delay transmission mechanism, etc.
Conclusion: The TCP/IP protocol does not deal with sticky packet problems in the transport layer.
Sticky Bag solution (essentially maintaining the boundaries of messages and messages at the application layer)
Fixed length Package
Baulinga \ r \ n (FTP)
Baotou Plus package length (below)
More complex application-layer protocols
programming Practices-readn && writen
Pipelines, FIFO and some devices (especially terminals and networks) have the following two properties:
1) The data returned by a read operation may be less than the requested data, even if it has not reached the end of the file, but this is not an error, should continue to read the device;
2) The return value of a write operation may also be less than the number of bytes specified. This may be caused by a factor, such as: Kernel buffer full ... This is not a mistake, however, and it should continue to write the rest of the data (usually, only non-blocking descriptors, or capture to a signal, only occurs when this write Midway back)
You have never seen this happen when you read and write disk files, unless the file system is running out of space, or if you are approaching the quota limit, you cannot write all the data that is required!
Typically, these features need to be considered when reading, writing a network device, pipe, or terminal. So, we have the following two functions: Readn and Writen, the function is to read \ Write the specified n-byte data, and to handle the case that the return value may be less than the required value:
ssize_t readnint fd, void *buf, size_t count); ssize_t writen (int fd, const void *buf, size_t count);
return value:
The number of bytes read \ Write; If an error occurs, return-1
Realize:
These two functions simply call the read and write system calls as many times as needed until you read \ Write n data
ssize_t readn (int fd,void *buf,size_t count) {size_t nleft = count; ssize_t nread = 0; Char *ptr = Static_cast<char *> (BUF); while (Nleft > 0) {if (nread = Read (fd,ptr,nleft)) < 0) {//a bit of things are not read if (nLe FT = = count) {return-1; Error} else {break; Error, return amount read so far}} else if (nread = = 0) {break; EOF} nleft-= Nread; PTR + = nread; } return count-nleft;} ssize_t writen (int fd, const void *buf, size_t count) {size_t nleft = count; ssize_t Nwritten; const char *ptr = static_cast<const char *> (BUF); while (Nleft > 0) {if (Nwritten = Write (fd,ptr,nleft)) < 0) {//A little something is not written if (Nleft = = count) {return-1; Error} else {Break Error, return amount write so far}} else if (Nwritten = = 0) {break; EOF} nleft-= Nwritten; PTR + = Nwritten; } return Count-nwritten;}
header plus message length programming practice
Message structure :
struct transstruct{ int m_length; Header: True data length for data m_text Char m_text[bufsiz]; Message: Save the actual data to be sent};
When transmitting: The first four bytes of length + messages
At the time of the ticker: read the first four bytes, find the length, and read the data according to the length.
Server-side complete code and resolution # include "Commen.h"//echo server WRITEN,READN version int main () {int SOCKFD = socket (af_inet,sock_stream,0); if (SOCKFD = =-1) {Err_exit ("socket error"); }//Add address multiplexing int optval = 1; if (setsockopt (sockfd,sol_socket,so_reuseaddr,&optval,sizeof (optval)) = =-1) {err_exit ("setsockopt so_reuse ADDR error "); }//bind struct sockaddr_in serveraddr; serveraddr.sin_family = af_inet; Serveraddr.sin_port = htons (8002); SERVERADDR.SIN_ADDR.S_ADDR = Inaddr_any; Bind any one of the IP addresses of the machine if (bind (SOCKFD, struct sockaddr *) &serveraddr,sizeof (serveraddr)) = =-1) {Err_exit ("bin D error "); }//Start the listening socket if (listen (sockfd,somaxconn) = =-1) {Err_exit ("Listen error"); } struct sockaddr_in peeraddr; socklen_t Peerlen = sizeof (PEERADDR); while (true) {//accept link int peersockfd = accept (SOCKFD, (struct sockaddr *) &peeraddr,&peerlen); if (PEERSOCKFD = =-1) {Err_exit ("Accept error"); }//Print customer information cout << "client:" << Endl; cout << "\tsin_port:" << ntohs (peeraddr.sin_port) << Endl; cout << "\tsin_addr:" << inet_ntoa (peeraddr.sin_addr) << Endl; cout << "\tsocket:" << peersockfd << Endl; Each client connection comes in, a sub-process is fork,//The corresponding business process is completed by the child process, and the parent process continues to listen pid_t PID = fork (); if (PID = =-1) {close (SOCKFD); Close (PEERSOCKFD); Err_exit ("fork Error"); } else if (PID = = 0)//Sub-process, processing business {close (SOCKFD); The child process closes the listener socket because the child process is not responsible for monitoring the task struct transstruct recvbuf; ssize_t readcount = 0; while (true) {memset (&recvbuf,0,sizeof (RECVBUF)); First, read the header length from the client if (Readcount = Readn (peersockfd,& (Recvbuf.m_length), 4)) = =-1) { Err_exit ("Readn error"); } else if (Readcount = = 0)//If the link is closed {peercloseprint ("C Lient Connect closed "); }//Read data if (Readcount = Readn (peersockfd,& (Recvbuf.m_text), recvbuf.m_length) according to the actual length of the message = =-1) {err_exit ("Readn error"); } else if (Readcount = = 0) {peercloseprint ("client connect closed"); }//write the whole message back to the client if (writen (peersockfd,&recvbuf,recvbuf.m_length+4) = =-1) {err_exit ("writen error"); } Recvbuf.m_text[recvbuf.m_length] = 0; Write to Terminal fputs (recvbuf.m_text,stdout); }} else if (PID > 0)//parent process {Close (PEERSOCKFD); }} close (SOCKFD); return 0;}
Client end complete code implementation and parsing # include "Commen.h" int main () {int SOCKFD = socket (af_inet,sock_stream,0); if (SOCKFD = =-1) {Err_exit ("socket error"); }//Fill in the server address and its port number struct sockaddr_in serveraddr; serveraddr.sin_family = af_inet; Serveraddr.sin_port = htons (8002); SERVERADDR.SIN_ADDR.S_ADDR = inet_addr ("127.0.0.1"); if (Connect (SOCKFD, struct sockaddr *) &serveraddr,sizeof (serveraddr)) = =-1) {err_exit ("connect error"); } int readcount = 0; struct Transstruct sendbuf; struct Transstruct recvbuf; Input data from the keyboard while (Fgets (sendbuf.m_text,sizeof (Sendbuf.m_text), stdin)! = NULL) {//The length of the real message is saved SENDBUF.M _length = strlen (Sendbuf.m_text); Send data to server .... +4 reason: You need to add the length of the 4-byte header of the first report if (writen (sockfd,&sendbuf,sendbuf.m_length+4) = =-1) { Err_exit ("Write socket error"); }///First, receive the length of the datagram to be sent from the server side if (Readcount = Readn (sockfd,& (Recvbuf.m_length), 4)) = =-1){err_exit ("read socket error"); } else if (Readcount = = 0) {peercloseprint ("client connect closed"); }//Then, according to the length of the message read from the server side, read the message if (Readcount = Readn (sockfd,& (Recvbuf.m_text), recvbuf.m_length)) = =-1) {err_exit ("read socket error"); } else if (Readcount = = 0) {peercloseprint ("client connect closed"); } Recvbuf.m_text[recvbuf.m_length] = 0; Write it back to Terminal fputs (recvbuf.m_text,stdout); memset (&sendbuf,0,sizeof (SENDBUF)); memset (&recvbuf,0,sizeof (RECVBUF)); } close (SOCKFD); return 0;}
complete code and analysis of -commen.h attached
#ifndef commen_h_included#define commen_h_included#include <unistd.h> #include <signal.h> #include < errno.h> #include <fcntl.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/stat.h > #include <sys/ipc.h> #include <sys/shm.h> #include <sys/msg.h> #include <sys/sem.h># Include <sys/socket.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include < Iostream>using namespace std;//message structure struct transstruct{int m_length; Header: True data length for data m_text Char M_text[bufsiz]; Message: Save the actual data to be sent};//error exit void Err_exit (std::string str) {perror (Str.c_str ()); Exit (exit_failure);} End close link exit void Peercloseprint (std::string str = "Peer Connect closed") {cout << str << Endl; _exit (0);} Signal capture function: The code in the previous blog needs to use the void onsignal (int signalnumber) {switch (signalnumber) { Case Sigusr1:cout << ' child receive SIGUSR1 ' << signalnumber << Endl; _exit (0); Case Sigusr2:cout << "parent receive SIGUSR2:" << signalnumber << Endl; _exit (0); Default:cout << "RECV othrer SIGNAL" << Endl; }}//Classic Readn function (source: apue) ssize_t readn (int fd,void *buf,size_t count) {size_t nleft = count; ssize_t nread = 0; Char *ptr = Static_cast<char *> (BUF); while (Nleft > 0) {if (nread = Read (fd,ptr,nleft)) < 0) {//a bit of things are not read if (nLe FT = = count) {return-1; Error} else {break; Error, return amount read so far}} else if (nread = = 0) {break; EOF} nleft-= Nread; PTR + = nread; } return count-nleft;} Classic writen function (source: apue) ssize_t writen (int fd, const void *buf, size_t count) { size_t nleft = count; ssize_t Nwritten; const char *ptr = static_cast<const char *> (BUF); while (Nleft > 0) {if (Nwritten = Write (fd,ptr,nleft)) < 0) {//A little something is not written if (Nleft = = count) {return-1; Error} else {break; Error, return amount write so far}} else if (Nwritten = = 0) {break; EOF} nleft-= Nwritten; PTR + = Nwritten; } return Count-nwritten;} #endif//commen_h_included
Socket Programming Practice (6) The reason and solution of--tcp sticky bag