当前位置:网站首页>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 market of plasma separator 2022-2028: Research Report on technology, participants, trends, market size and share
- 10個 Istio 流量管理 最常用的例子,你知道幾個?
- MySql數據庫root賬戶無法遠程登陸解决辦法
- npm命令--安装依赖包--用法/详解
- 查询mysql数据库中各表记录数大小
- PTA tiantisai l1-078 teacher Ji's return (15 points) detailed explanation
- How to execute an SQL statement in MySQL
- Basic use of MySQL (it is recommended to read and recite the content)
- 颠覆你的认知?get和post请求的本质
- Stable Huawei micro certification, stable Huawei cloud database service practice
猜你喜欢
Yyds dry goods inventory web components series (VII) -- life cycle of custom components
Figure application details
Basic use of MySQL (it is recommended to read and recite the content)
关于进程、线程、协程、同步、异步、阻塞、非阻塞、并发、并行、串行的理解
MySQL learning record 13 database connection pool, pooling technology, DBCP, c3p0
What is the difference between gateway address and IP address in tcp/ip protocol?
Cross domain and jsonp details
Basic knowledge of binary tree, BFC, DFS
[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
CADD课程学习(7)-- 模拟靶点和小分子相互作用 (柔性对接 AutoDock)
随机推荐
DM8 archive log file manual switching
关于进程、线程、协程、同步、异步、阻塞、非阻塞、并发、并行、串行的理解
The global and Chinese market of negative pressure wound therapy unit (npwtu) 2022-2028: Research Report on technology, participants, trends, market size and share
2/10 parallel search set +bfs+dfs+ shortest path +spfa queue optimization
Data processing methods - smote series and adasyn
tengine 内核参数
Practical development of member management applet 06 introduction to life cycle function and user-defined method
2328. 网格图中递增路径的数目(记忆化搜索)
Use js to complete an LRU cache
Deep learning framework installation (tensorflow & pytorch & paddlepaddle)
R note prophet
Unity中几个重要类
图应用详解
How to execute an SQL statement in MySQL
题解:《单词覆盖还原》、《最长连号》、《小玉买文具》、《小玉家的电费》
User datagram protocol UDP
满足多元需求:捷码打造3大一站式开发套餐,助力高效开发
hashlimit速率控制
Yyds dry goods inventory hcie security Day11: preliminary study of firewall dual machine hot standby and vgmp concepts
During pycharm debugging, the view is read only and pause the process to use the command line appear on the console input