Application of out-of-band data
If a client program needs to cancel a request that has been written to the server for some reason, it needs to send an emergency request to the server.
The actual program example using out-of-band data is telnet, rlogin, and FTP commands.
The first two programs (Telnet and rlogin) Send the stop character as emergency data to the remote end. This allows the remote end to flush all unprocessed inputs and discard all unsent terminal outputs. This will quickly interrupt a running process that sends a large amount of data to our screen.
The FTP command uses out-of-band data to interrupt the transmission of a file.
TCP out-of-band data (TCP emergency data)
TCP has no real out-of-band data. To send important protocols, TCP provides a mechanism called urgent mode.URG bitIndicates entering the emergency mode. The receiver can take special measures for the emergency mode. It is easy to see that,In this way, data is not easily congested., You canCapture in the server programThe sigurg signal is used to receive data in a timely manner or the Recv function with the OOB mark is used to accept.
Oobserver. c
# Include <stdio. h> # include <stdlib. h> # include <errno. h> # include <string. h> # include <sys/types. h> # include <netinet/in. h> # include <sys/socket. h> # include <sys/Wait. h> # include <unistd. h> # include <fcntl. h>/* local port to be monitored by the server */# define myport 4000/* Number of connections without accept allowed at the same time */# define backlog 10int new_fd =-1; // when the global variable is connected to the socket main function and the sigurg signal processing function, void sig_urg (INT signo) is called; void main () {/* listens on sock_fd, new_fd accepts new connections */INT sockfd;/* your own address information */struct sockaddr_in my_addr;/* The address information of the connector */struct sockaddr_in their_addr; int sin_size; int N; char buff [100];/* is used to store the variable of the previous default sigurl processor */void * old_sig_urg_handle;/* here is the error check we have always stressed. if an error occurs when socket () is called, */If (sockfd = socket (af_inet, sock_stream, 0) =-1) is returned) {/* output error message and exit */perror ("socket"); exit (1);}/* Host byte sequence */my_addr.sin_family = af_inet;/* network byte sequence, short integer */my_addr.sin_por T = htons (myport);/* fill the IP address of the machine running the program into s_addr */my_addr.sin_addr.s_addr = inaddr_any; /* clear the remaining space of this structure */bzero (& (my_addr.sin_zero), 8);/* here is the error check we have always stressed !! */If (BIND (sockfd, (struct sockaddr *) & my_addr, sizeof (struct sockaddr) =-1) {/* If BIND () fails to be called, the error message is displayed. Exit */perror ("bind"); exit (1) ;}/ *. Here is the error check we have always stressed !! */If (Listen (sockfd, backlog) =-1) {/* If the Listen Call fails, an error message is displayed. Exit */perror ("listen "); exit (1);}/* Set sigurg's processing function sig_urg */old_sig_urg_handle = signal (sigurg, sig_urg ); /* create our process as the owner of the Set interface * // wrong; non-listening socket/* If (fcntl (sockfd, f_setown, getpid () =-1) {perror ("fcntl"); exit (1) ;}*/while (1) {/* here is the main accept () loop */sin_size = sizeof (struct sockaddr_in ); /* here is the error check we have always stressed !! */If (new_fd = accept (sockfd, (struct sockaddr *) & their_addr, & sin_size) =-1) {/* if an error occurs when you call accept, an error message is displayed. Enter the next loop */perror ("accept"); continue;} // printf ("in main, new_fd = % d \ n", new_fd ); fcntl (new_fd, f_setown, getpid (); // set our process to the owner of the connection socket/* the server displays the connection information */printf ("server: got connection from % s \ n ", inet_ntoa (their_addr.sin_addr);/* a sub-process will be established to communicate with the socket just created * // If (! Fork () if (1) {While (1) {If (n = Recv (new_fd, buff, sizeof (buff)-1, 0) = 0) {printf ("received EOF \ n"); break;} buff [N] = '\ 0'; printf ("Recv % d Bytes: % s \ n", n, buff) ;}}/* close the socket connection represented by new_fd */close (new_fd);}/* wait for all sub-processes to exit */while (waitpid (-1, null, wnohang)> 0);/* restore the previous sigurg processor */signal (sigurg, old_sig_urg_handle);} void sig_urg (INT signo) {int N; char buff [100]; printf ("sigurg received \ n"); // printf ("in sig_urg (), new_fd = % d \ n", new_fd ); // while (n = Recv (new_fd, buff, sizeof (buff)-1, MSG_OOB) =-1); n = Recv (new_fd, buff, sizeof (buff)-1, MSG_OOB); If (n> 0) {buff [N] = '\ 0'; printf ("Recv % d OOB byte: % s \ n ", N, buff);} else {perror (" Recv ");}}
Oobclient. c
# Include <stdio. h> # include <stdlib. h> # include <errno. h> # include <string. h> # include <netdb. h> # include <sys/types. h> # include <netinet/in. h> # include <sys/socket. h>/* server program listening port number */# Define port 4000/* Maximum number of bytes we can receive at a time */# define maxdatasize 100int main (INT argc, char * argv []) {/* socket descriptor */INT sockfd, numbytes; char Buf [maxdatasize]; struct hostent * He; /* host information of the connector */struct sockaddr_in their_addr;/* Check parameter information */I F (argc! = 2) {/* if there is no parameter, use the method and exit */fprintf (stderr, "Usage: client hostname \ n"); exit (1 );} /* obtain host information */If (He = gethostbyname (argv [1]) = NULL) {/* If gethostbyname () is incorrect, then the error message is displayed and exit */herror ("gethostbyname"); exit (1);} If (sockfd = socket (af_inet, sock_stream, 0) =-1) {/* If a socket () call error occurs, the error message is displayed and the */perror ("socket"); exit (1 );} /* Host byte sequence */their_addr.sin_family = af_inet;/* network byte sequence, short integer */their_addr.sin_port = H Tons (port); their_addr.sin_addr = * (struct in_addr *) He-> h_addr);/* clear the remaining parts of the structure */bzero (& (their_addr.sin_zero), 8 ); if (connect (sockfd, (struct sockaddr *) & their_addr, sizeof (struct sockaddr) =-1) {/* If the connect () connection fails, the error message is displayed. Exit */perror ("Connect"); exit (1);} If (send (sockfd, "5", 1, MSG_OOB) =-1) {perror ("send"); close (sockfd); exit (0);} printf ("send 1 byte of OOB data \ n "); sleep (2);/* here is the error check we mentioned! */If (send (sockfd, "123", 3, 0) =-1) // 123 normal data {/* if an error occurs, an error message is displayed, close the new connection and exit */perror ("send"); close (sockfd); exit (0 );} printf ("Send 3 byte of normal data \ n");/* sleep 1 second */sleep (2); If (send (sockfd, "4", 1, MSG_OOB) =-1) {perror ("send"); close (sockfd); exit (0);} printf ("send 1 byte of OOB data \ n "); sleep (2); If (send (sockfd, "56", 2, 0) =-1) // 56 normal data {perror ("send "); close (sockfd); exit (0);} printf ("Send 2 bytes of normal data \ n"); sleep (2); If (send (sockfd, "7 ", 1, MSG_OOB) =-1) {perror ("send"); close (sockfd); exit (0 );} printf ("send 1 byte of OOB data \ n"); sleep (2); If (send (sockfd, "89", 2, MSG_OOB) =-1) {perror ("send"); close (sockfd); exit (0);} printf ("Send 2 bytes of OOB data \ n"); sleep (2 ); /* If (send (sockfd, "ABC", 3, MSG_OOB) =-1) {perror ("send"); close (sockfd); exit (0 );} printf ("Send 3 bytes of OOB data \ n"); sleep (2); If (send (sockfd, "ABC", 3, MSG_OOB) =-1) {perror ("send"); close (sockfd); exit (0);} printf ("Send 3 bytes of OOB data \ n"); sleep (2 ); */close (sockfd); Return 0 ;}
Running result:
Notes:
1. send and receive out-of-band data
01. How does the sender send out-of-band data?
Note that only the tcp urg flag is included in the data sent once by TCP, it does not contain the OOB data we sent (when the data before oob in the sent data queue has reached the length limit of TCP packets ).
If (send (new_fd, "4", 1, MSG_OOB) =-1)
{
Perror ("send ");
Close (new_fd );
Exit (0 );
}
Printf ("send1 byte of OOB data \ n ");
02. How does the receiver receive out-of-band data?
/* Set the processing function sig_urg */
Old_sig_urg_handle = signal (sigurg, sig_urg );
Voidsig_urg (INT signo)
{
INTN;
Charbuff [100];
Printf ("sigurgreceived \ n ");
N = Recv (new_fd, buff, sizeof (buff)-1, MSG_OOB );
Buff [N] = 0;
Printf ("Recv % d OOB byte: % s \ n", N, buff );
}
2. send (sendfd, "ABC", 3, MSG_OOB). Three bytes of OOB data are sent. however, TCP only supports one byte of OOB. Do you lose two bytes?
TCP sets URG in URG emergency mode, and the emergency pointer locates the third byte ("C") (no matter where it is located, an emergency pointer is used to locate the OOB byte. The first two bytes ("AB") are sent as normal bytes. in fact, TCP always treats the last byte as OOB data, and others as normal bytes. no matter how many bytes of OOB data you send through the sendxxx function with the MSG_OOB mark, the sender only regards the last byte as OOB data, and the receiver can only receive one byte of OOB data.
3. fcntl (new_fd, f_setown, getpid (); // set our process to the owner of (connect socket, instead of listening to socket)
4. When a sub-process is created to receive normal data, the out-of-band data cannot be normally received...
Appendix:
Signal Processing
UNIX systems call signal () to receive a specified type of signal and specify the corresponding method. This means that signal () canAssociate a specified processing function with a signal.
Function prototype
Int signal (INT Sig, _ sighanler_t handler); // SIG is the signal type to be processed, handler is the action associated with the signal, which can be a function address, it can also be sig_ign (ignoring the signal) and sig_dfl (restoring the system's default signal processing ).
Function return value
If the call is successful, the association of the signal before this signal call is returned.
Eg:
Void sig_urg (INT signo );
/* Used to store the variable of the previously default sigurl processor */
Void * old_sig_urg_handle;
/* Set the processing function sig_urg */
Old_sig_urg_handle = signal (sigurg, sig_urg );
******
* ** Data Processing ****.
******
/* Restore the previous sigurg processor */
Signal (sigurg, old_sig_urg_handle );
(2) Use signals to drive I/O operations on a socket
Let the kernel use signals to notify us when the file descriptor (socket) is ready.
To use a signal to drive I/O operations on a socket, the following three steps are required.
(1) One and sigio signal processing function must be set.
(2) socketOwner (process)Must be set. Generally, the f_setown parameter of the fcntl function is used to set the owner. So that there are clear processes to receive signals when a socket is ready.
(3) The socket must be allowed to use asynchronous I/O. It is generally implemented by calling the f_setfl command of the fcntl function, and o_async is the parameter.
Eg:
1. First, set a processing function for the sigio signal to read and process data in the input cache.
Signal (sigio, void (* getmyinput) (int signum ));
2. Set a process for receiving sigio signals. Use the fcntl function.
Fcntl (my_fd, f_setown, getpid ());
3. Obtain the state flag set of the file descriptor and add an o_async attribute to the state flag set.
Int flags = fcntl (my_fd, f_getfl );
Fcntl (my_fd, f_setfl, flags | o_async );