Linux network programming | advanced network programming

Network advanced programming

There are mainly 4 IO models under Linux

  • Blocking IO: the most commonly used, by default the socket is in blocking IO mode after it is established
  • Non-blocking IO: can prevent the process from blocking on IO operations, polling is required
  • Signal-driven IO: an asynchronous communication model
  • IO multiplexing: allows multiple IOs to be controlled at the same time

In practical applications, it is usually the case that multiple clients connect to the server. If a blocking function is used, if the resource is not ready, the process that calls the function will go to sleep, so that it cannot handle other requests. This section gives three methods to solve IO multiplexing, namely non-blocking and asynchronous processing (using the fcntl() function), and multiplexing processing (using the select() function or poll() function) . In addition, there are multi-processes and multi-threads, which are commonly used transaction processing methods in network programming

1. Non-blocking

When we set a socket to non-blocking mode, it is equivalent to telling the kernel: "When the IO operation I requested cannot be completed immediately, and you want my process to sleep and wait, do not do this, please return immediately. Give me the error". When an application uses a socket in non-blocking mode, it needs to use a loop to continuously test whether a file descriptor has data to read (called polling)

  • Use fcntl(int fd, int cmd, int arg) function to set non-blocking mode
  • cmd is set to F_SETFL
  • arg is set to O_NONBLOCK
/*****设置非阻塞IO模式*****/
int flag = fcntl(sockfd, F_GETFL);	//cmd为F_GETFL即返回fd指向的文件的状态
flag |= O_NONBLOCK;
fcntl(sockfd, F_SETFL, flag);

2. Asynchronous IO

The use of blocking and non-blocking and multiplexing mechanisms can effectively carry out network communication, but the most efficient method is to use the asynchronous notification mechanism, which is the most common in device IO programming. The kernel sends a SIGIO signal to a certain process by using asynchronous IO when the time that needs to be processed occurs. In this way, the application does not need to constantly wait for certain events to occur, but can run down to complete other tasks. Only when you receive the SIGIO signal from the kernel, you can handle it.

  • Use the fcntl(int fd, int cmd, int arg) function to set the asynchronous IO mode
  • Use the F_SETOWN command of the fcntl() function to make the socket belong to the current process
  • Use the F_SETFL command of the fcntl() function to set arg to O_ASYNC
/*****设置异步IO模式*****/
fcntl(sockfd, F_SETOWN, getpid());	//将套接字归属于该进程,使内核判断应该向哪个进程发送信号
int flag = fcntl(sockfd, F_GETFL);	//cmd为F_GETFL即返回fd指向的文件的状态
flag |= O_ASYNC;
fcntl(sockfd, F_SETFL, flag);

3. Multiplexing IO

The application processes multiple input and output streams at the same time. If the blocking mode is used, the expected purpose will not be achieved; if the non-blocking mode is used, polling multiple inputs will waste CPU time; if multiple processes are set to process separately A data link, synchronization and communication between new processes will complicate the program; a better way is to use IO multiplexing, the basic idea is:

  • First construct a table of related descriptors, and then call a function. The function returns when one or more of these file descriptors are ready for I/O
  • When the function returns, tell the process which descriptor is ready for I/O operations

Use select() / poll() functions to achieve multiplexing:

/*****select()函数*****/
函数原型:int select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
传 入 值:maxfd 所有文件描述符的最大值加1
		 readfds 所有要读的文件的文件描述符的集合
		 writefds 所有要写的文件的文件描述符的集合
		 exceptfds 其他要向我们通知的文件描述符
		 timeout 超时设置 -->NULL:一直阻塞,直到有文件描述符就绪或出错
		 				 -->0:仅仅检测文件描述符集的状态,然后立即返回
		 				 -->不为0:在指定时间内,如果没有事件发生,则超时返回

When the select() function is called, the process will block until there is a file to read, a file to write, or the timeout period expires. In order to set the file descriptor need to use several macros:

#include <sys/select.h>
int FD_ZERO(fd_set *fdset);			//从fdset中清除所有的文件描述符
int FD_CLR(int fd,fd_set *fdset);	//将fd从fdset中清除
int FD_SET(int fd,fd_set *fdset);	//将fd加入到fdset
int FD_ISSET(int fd,fd_set *fdset);	//判断fd是否在fdset集合中
/*例如*/
fd_set rset;
int fd;
FD_ZERO(&rset);
FD_SET(fd,&rset);
FD_SET(stdin&rset);
//在select返回之后,可以使用FD_ISSET(fd,&rset)测试给定的位置是否置位。
if(FD_ISSET(fd,&rset))
{
    
    ......}

The figure below shows the TCP multiplexing model
Insert picture description here

Guess you like

Origin blog.csdn.net/Chuangke_Andy/article/details/108437802