c/c++linux background development blood washing notes 2.2.2 application of reactor in network components

Network programming concerns

Connection establishment

It is divided into two types: the server handles the connection of the receiving client, and the server connects to the third-party service as the client;

int clientfd = accept(listenfd, addr, sz);

int connectfd = socket(AF_INET, SOCK_STREAM, 0); 
connect(connectfd, (struct sockaddr *)&addr, sizeof(addr));

Disconnection of connection

There are two types: active disconnection and passive disconnection;

// Active shutdown 
close(fd); 
shutdown(fd, SHUT_RDWR); 
// Actively close the local read end and the peer write segment 
shutdown(fd, SHUT_RD); 
// Actively close the local write end and the peer read segment 
shutdown(fd, SHUT_WR); 

// Passive: read end off 
int n = read(fd, buf, sz); 
if (n == 0) { 
	close_read(fd); 
	// close(fd);
}

// Passive: write side off 
int n = write(fd, buf, sz); 
if (n == -1 && errno == EPIPE) { 
	close_write(fd); 
	// close(fd);
}

close_read and close_write is a function written by ourselves. Generally, we can close it directly

Arrival of message

Reading data from the read buffer;

int n = read(fd, buf, sz);
if (n < 0) { //n == -1
	if (errno == EINTR || errno == EWOULDBLOCK)
		break;
	close(fd);
} else if (n == 0) {
	close(fd);
} else {
	// Processing buf
}

Message sent

Write data to the write buffer;

int n = write(fd, buf, sz);
if (n == -1) {
	if (error == EINTR || errno == EWOULDBLOCK) {
		return;
	}
}

Note the difference between read and write. In non blocking IO, if read is not completed at one time, the number of characters written will be returned. If write is not completed, no data will be written. If write can be completed, all data will be written.

Network IO charge

Detect IO

The io function itself can detect the state of io; However, only one fd corresponding state can be detected;
io multiplexing can detect the status of multiple IOS at the same time;
The difference is that the io function can detect the specific state;
io multiplexing can only detect readable, writable, error, disconnection and other general events;

Operation IO

Only io functions can be used for operation; There are two operation modes: blocking io and non blocking io;

Blocking IO and non blocking IO

  • Blocking threads on the network;
  • The fd blocking attribute of the connection determines whether the io function is blocked;
  • The specific difference is: whether the io function returns immediately when the data does not arrive;
// By default, fd is blocked. The method to set non blocking is as follows:;
int flag = fcntl(fd, F_GETFL, 0); 
fcntl(fd, F_SETFL, flag | O_NONBLOCK);

IO multiplexing

epoll

Structure and interface

Red black tree – save all fd and events monitored, and a data (fd or ptr) pointing to the user space
Two way linked list – save the fd that listens to the event and copy it to epoll_ In the user queue (array) provided by wait

Connection establishment

//Processing requests
struct epoll_event ev = {0};
ev.events |= EPOLLIN;
epoll_ctl(efd, EPOLL_CTL_ADD, listenfd, &ev);
...
clientfd = accept(...)
ev.events |= EPOLLIN;
epoll_ctl(efd, EPOLL_CTL_ADD, clientfd, &ev);

//Handling non blocking links
int connectfd = socket(AF_INET, SOCK_STREAM, 0);
connect(connectfd, (struct sockaddr *)&addr, sizeof(addr));
struct epoll_event ev;
ev.events |= EPOLLOUT;
epoll_ctl(efd, EPOLL_CTL_ADD, connectfd, &ev);
//When the write event is triggered, the connection is established successfully
if (status == e_connecting && e->events & EPOLLOUT) {
	status == e_connected;
}

Disconnected

if (e->events & EPOLLRDHUP) close_read(fd); //Read end off
if (e-e->events & EPOLLHUP) close(fd);      //Both read and write are turned off

Data arrival

if (e->events & EPOLLIN) {
	int n = read(fd, buf, sz);
	if (n<0) {
		if(errno == EINTR)
			continue; //read again
		if (errno == EWOULDBLOCK)
			break; //read next time
		close(fd);
	} else if (n == 0) {
		close_read(fd);
	}
}

Data transmission completed

if (e->events & EPOLLOUT) {
	int n = write(fd, buf, dz);
	if (n == -1) {
		if(errno == EINTR)
			continue; //try again
		if (errno == EWOULDBLOCK) {
			struct epoll_event ev;
			ev.events = EPOLLOUT;
			epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
		} else {
			close(fd);
		}
	} else { // n > 0, success
		epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
	}
}

reactor application

The reactor design pattern is an event handling pattern for handling
service requests delivered concurrently to a service handler by one or more inputs
The service handler then demultiplexes the
incoming requests and dispatches them synchronously to the associated request
handlers.

Single reactor

redis

Multiple reactor

Multithreading
memcache,nginx

reference material

[1] Zero sound education c/c++linux background development 2.2.2

Keywords: C Linux Back-end server

Added by baudday on Sat, 27 Nov 2021 23:17:52 +0200