当前位置:网站首页>Implementation of knowledge consolidation source code 1: epoll implementation of TCP server
Implementation of knowledge consolidation source code 1: epoll implementation of TCP server
2022-07-06 04:17:00 【yun6853992】
1: Background description
tcp Network communication is a business function that is often repeated in daily business
===》 dependent socket Interface :socket,bind,listen,accept,send,recv Are all familiar to us
===》 dependent io Multiplexing scheme :select,poll,epoll You can choose to use it according to the business scenario
===》 But in fact , Simple tcp In the process of server implementation , There are always some details to pay attention to ,
===》 And consider every re implementation , Rewrite... Many times , Start thinking about backing up some code ....
2:tcp Server source code of demo(epoll Monitor client connections and business processing )
As tcp Server for , Use epoll Listen for readable events ( monitor accept Connect , And listening and receiving ), Conduct business processing .
there epoll Adopted ET Pattern .
You can use the network serial port tool to test , Or realize a tcp The client of .
My code is in linux Environmental use gcc Compiled and tested , The test passed .
Code details you can pay attention to :
===》 Set up socket fd Non blocking
===》 Set ports to be reusable
===》 as well as epoll Event management
/************************************************ info: Realization tcp Server code Listening port , Get the connection to the client , And analyze the data data: 2022/02/10 author: hlp ************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
// Realization tcp Server function of
//1: establish socket
//2:bind listen accept
//3:recv send
//4: Set up fd reusable , Non blocking .
//5: How to use io Multiplexing ? What if we use the event mechanism ?
#define VPS_PORT 9999
// establish socket
int vps_init_socket();
// establish epoll And conduct event listening and processing
void vsp_socket_exec(int listenfd);
int main()
{
int fd = vps_init_socket();
if(fd < 0)
{
printf("create vps socket fd error. \n");
return -1;
}else
{
printf("create vps socket fd success. \n");
}
//epoll monitor Callback for processing
vsp_socket_exec(fd);
printf("vps socket end. \n");
return 0;
}
// Set up fd Non blocking By default fd It's blocked
int SetNonblock(int fd) {
int flags;
flags = fcntl(fd, F_GETFL, 0);
if (flags < 0)
return flags;
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) < 0)
return -1;
return 0;
}
// establish Server side socket, there ip and port It's dead
int vps_init_socket()
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd < 0)
{
printf("create socket error. \n");
return -1;
}
// Set up fd Non blocking Set ports to be reusable
SetNonblock(fd);
int optval = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int));
// Definition fd Related parameters
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(VPS_PORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(fd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)) < 0)
{
printf("vps socket bind error \n");
return -1;
}
// Set up fd For passive sockets for accept use Set up listen The size of the queue
if(listen(fd , 20) < 0)
{
printf("vps socket listen error \n");
return -1;
}
printf("create and set up socket success. start accept.. \n");
return fd;
}
// Can be combed socket Associated interface Non blocking And parameters Network byte order correlation
/* #include <netinet/in.h> typedef uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; }; struct sockaddr_in { __SOCKADDR_COMMON (sin_); in_port_t sin_port; struct in_addr sin_addr; unsigned char sin_zero[sizeof (struct sockaddr) - __SOCKADDR_COMMON_SIZE - sizeof (in_port_t) - sizeof (struct in_addr)]; };*/
// establish epoll Return the epollfd Failure to return -1
int create_epoll_and_add_listenfd(int listenfd);
// As a server Has been to epoll monitor Business processing
int vps_epoll_wait_do_cycle(int epfd, int listenfd);
// Events trigger Processing connection requests
int vps_accept_exec(int epfd, int listenfd);
// Events trigger Processing readable requests Reading data There is no monitor to write here , I understand that the business is not complicated and frequent , I write and send directly
int vps_recv_exec(int epfd, int connfd);
// establish epoll monitor acceptfd, Listen to the logic of receiving and sending
void vsp_socket_exec(int listenfd)
{
// establish epollfd, And join the listening node
int epollfd = -1;
if((epollfd = create_epoll_and_add_listenfd(listenfd)) <0)
{
printf("create epollfd error. \n");
close(listenfd);
return ;
}
printf("create epollfd [%d] success, start epoll wait... \n", epollfd);
// Use epoll_wait Yes epoll monitor
vps_epoll_wait_do_cycle(epollfd, listenfd);
return;
}
// establish epoll And give epoll Add a listening node EPOLL_ADD listenfd
int create_epoll_and_add_listenfd(int listenfd)
{
// establish epoll
int epfd = -1;
epfd = epoll_create(1); // Parameter ignored must be greater than 0
if(epfd == -1)
{
printf("create vsp epoll error. \n");
return -1;
}
//epoll_ctl Join a node
struct epoll_event event;
event.data.fd = listenfd;
event.events = EPOLLIN | EPOLLET; // Monitor access use ET
if(epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &event) == -1)
{
printf("vps epoll add listenfd error. \n");
close(epfd);
return -1;
}
printf("vps epoll create success and add listenfd success.[%d] \n", epfd);
return epfd;
}
// Use epoll_wait Yes epfd monitor And then business processing
int vps_epoll_wait_do_cycle(int epfd, int listenfd)
{
struct epoll_event event_wait[1024];
int nready = 0;
while(1) // If multithreading You should set the termination flag here
{
//int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
nready = epoll_wait(epfd, event_wait, 1024, 1000);
if(nready < 0)
{
if (errno == EINTR)// The signal is interrupted
{
printf("vps epoll_wait return and errno is EINTR \n");
continue;
}
printf("vps epoll_wait error.[%s]\n", strerror(errno));
break;
}
if(nready == 0)
{
continue;
}
// There are already related events triggered here Conduct business processing
for(int i = 0; i<nready; i++)
{
// Process readable , distinguish listenfd
if(event_wait[i].events & EPOLLIN)
{
if(event_wait[i].data.fd == listenfd)
{
// Handle accept It should listen and read here No listening and writing
vps_accept_exec(epfd, event_wait[i].data.fd);
}else
{
// Handle recv, It is possible that the opposite end is actively closed ,
vps_recv_exec(epfd, event_wait[i].data.fd);
}
}
// In this case, we should start from epoll Remove , And shut down fd
// If it is not the business that the client terminates after sending it , Are we not del, There are only exceptions del
if (event_wait[i].events & (EPOLLERR | EPOLLHUP)) //EPOLLHUP Have finished reading
{
printf("epoll error [EPOLLERR | EPOLLHUP].\n");
epoll_ctl(epfd, EPOLL_CTL_DEL, event_wait[i].data.fd, NULL);
close(event_wait[i].data.fd);
}
}
}
return 0;
}
// The general design is After receiving Delete event Listen for readable Events , Insert the reply string , Listen for writable events to send .
// Either use reactor The mode handles reception and transmission here or , Don't pay attention to the monitoring of sending for the time being , Business is not sent frequently here , Therefore, the necessary data will be returned directly after receiving
// Events trigger Processing connection requests
int vps_accept_exec(int epfd, int listenfd)
{
// There is a link need epoll receive epoll_ctl Add listening for readable Events
struct sockaddr_in cliaddr;
socklen_t clilen = sizeof(struct sockaddr_in);
//et Pattern Take out all the connections
int clifd = -1;
int ret = 0;
while(clifd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen))
{
//accept Returns a nonnegative integer normally Return... On error -1 This debug Debug it
if(clifd == -1)
{
// The resource is temporarily unavailable You should try again But you should not retry indefinitely
if (((errno == EAGAIN) || (errno == EWOULDBLOCK) )&& ret <3)
{
ret++;
continue;
}
printf(" accept error: [%s]\n", strerror(errno));
return -1;
}
// For those already connected fd To deal with Should join epoll
SetNonblock(clifd);
// Join in epoll
struct epoll_event clifd_event;
clifd_event.data.fd = clifd;
clifd_event.events = EPOLLIN | EPOLLET; //ET The mode should be read circularly
if(epoll_ctl(epfd, EPOLL_CTL_ADD, clifd, &clifd_event) == -1)
{
printf("vps accetp epoll ctl error . \n");
close(clifd);
return -1;
}
printf("accept success. [%d:%s:%d] connected \n",clifd, inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
}
return 0;
}
// Events trigger Processing readable requests Reading data There is no monitor to write here ,
int vps_recv_exec(int epfd, int connfd)
{
// Here is the real business process , Receive data and actively send a return data .
// If there's data Receive Until the reception is finished , Close the connection
printf("start recv data from client [%d].",connfd);
// Business scenarios are not frequent here The client terminates every time it sends ?
// Try to let the client actively disconnect ,
// You can implement a timer by yourself , Detect active disconnect processing
char recv_data[1024] = {
0};
int datalen = -1;
// There may be a signal interruption The receiving length is -1 Scene
while(1){
// Can't take ==0 Add here Otherwise, it will loop when the client is disconnected
while((datalen = read(connfd, recv_data, 1024)) > 0 )
{
printf("recv from [%d] data len[%d], data[%s] \n", connfd, datalen, recv_data);
memset(recv_data, 0, 1024);
}
// Shut down on the client When disconnected The receiving length is 0
printf("recv from [fd:%d] end \n", connfd);
// Send a reply message to the received message Here you can save some fd And the client ip and port Correlation , Construct reply message
const char * send_data = "hi i have recv your msg \n";
if(strlen(send_data) == write(connfd, send_data, strlen(send_data)))
{
printf("send buff succes [len:%lu]%s", strlen(send_data), send_data);
}
// The server receives empty packets because the client is shut down , The corresponding... Should be closed fd And from epoll Remove
if(datalen == 0)
{
if(epoll_ctl(epfd, EPOLL_CTL_DEL, connfd, 0) == -1)
{
printf("vps [fd:%d] close ,remove from epoll event error\n", connfd);
}else
{
printf("vps [fd:%d] close ,remove from epoll event success\n", connfd);
close(connfd);
}
break;
}
// be equal to 0 It may be the end of the reading
if(datalen == -1)
{
printf("recv end error: [%s]\n", strerror(errno));// Inevitable trigger Has received
if (errno == EWOULDBLOCK && errno == EINTR) // Don't deal with it
{
continue;
}
// Do you want to remove this fd Well ? Treat as removed tcp Short connection
// if(epoll_ctl(epfd, EPOLL_CTL_DEL, connfd, 0) == -1)
// {
// printf("vps client [%d] remove from epoll error\n", connectfd);
// }else
// {
// printf("vps client [%d] remove from epoll success\n", connectfd);
// }
// close(connfd);
break;
}
}
return 0;
}
3: Code testing
I use network tools to test :
I started trying to accumulate some common code : Spare in your own code base
More of my knowledge comes from here , I recommend you understand :Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK, Streaming media ,CDN,P2P,K8S,Docker,TCP/IP, coroutines ,DPDK Etc , Learn now
边栏推荐
- Global and Chinese markets for fire resistant conveyor belts 2022-2028: Research Report on technology, participants, trends, market size and share
- Detailed explanation of serialization and deserialization
- R note prophet
- 1291_Xshell日志中增加时间戳的功能
- Mysql数据库慢sql抓取与分析
- Patent | subject classification method based on graph convolution neural network fusion of multiple human brain maps
- IDEA编译JSP页面生成的class文件路径
- Lora gateway Ethernet transmission
- . Net interprocess communication
- Lombok principle and the pit of ⽤ @data and @builder at the same time
猜你喜欢
Guitar Pro 8.0最详细全面的更新内容及全部功能介绍
[PSO] Based on PSO particle swarm optimization, matlab simulation of the calculation of the lowest transportation cost of goods at material points, including transportation costs, agent conversion cos
综合能力测评系统
In depth MySQL transactions, stored procedures and triggers
Lombok原理和同时使⽤@Data和@Builder 的坑
TCP/IP协议里面的网关地址和ip地址有什么区别?
Basic knowledge of binary tree, BFC, DFS
Understanding of processes, threads, coroutines, synchronization, asynchrony, blocking, non blocking, concurrency, parallelism, and serialization
Web components series (VII) -- life cycle of custom components
查询mysql数据库中各表记录数大小
随机推荐
Practical development of member management applet 06 introduction to life cycle function and user-defined method
Global and Chinese markets for medical gas manifolds 2022-2028: Research Report on technology, participants, trends, market size and share
Yyds dry goods inventory web components series (VII) -- life cycle of custom components
P3033 [usaco11nov]cow steelchase g (similar to minimum path coverage)
The Research Report "2022 RPA supplier strength matrix analysis of China's banking industry" was officially launched
2/11 matrix fast power +dp+ bisection
HotSpot VM
lora网关以太网传输
pd. to_ numeric
综合能力测评系统
Figure application details
Basic use of MySQL (it is recommended to read and recite the content)
[leetcode question brushing day 33] 1189 The maximum number of "balloons", 201. The number range is bitwise AND
[FPGA tutorial case 11] design and implementation of divider based on vivado core
Several important classes in unity
2328. 网格图中递增路径的数目(记忆化搜索)
查询mysql数据库中各表记录数大小
Ipv4中的A 、B、C类网络及子网掩码
npm命令--安装依赖包--用法/详解
深入浅出node模板解析错误escape is not a function