当前位置:网站首页>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
边栏推荐
- 满足多元需求:捷码打造3大一站式开发套餐,助力高效开发
- HotSpot VM
- math_ Derivative function derivation of limit & differential & derivative & derivative / logarithmic function (derivative definition limit method) / derivative formula derivation of exponential functi
- DM8 archive log file manual switching
- Benefits of automated testing
- P3500 [poi2010]tes intelligence test (two points & offline)
- MLAPI系列 - 04 - 网络变量和网络序列化【网络同步】
- [adjustable delay network] development of FPGA based adjustable delay network system Verilog
- 1008 circular right shift of array elements (20 points)
- POI add border
猜你喜欢

How does technology have the ability to solve problems perfectly

1291_ Add timestamp function in xshell log

Database, relational database and NoSQL non relational database

JVM garbage collector concept

Web components series (VII) -- life cycle of custom components

Basic use of MySQL (it is recommended to read and recite the content)

View 工作流程

Stc8h development (XII): I2C drive AT24C08, at24c32 series EEPROM storage
![[FPGA tutorial case 11] design and implementation of divider based on vivado core](/img/39/f337510c2647d365603a8485583a20.png)
[FPGA tutorial case 11] design and implementation of divider based on vivado core

10 exemples les plus courants de gestion du trafic istio, que savez - vous?
随机推荐
Deep learning framework installation (tensorflow & pytorch & paddlepaddle)
/usr/bin/gzip: 1: ELF: not found/usr/bin/gzip: 3: : not found/usr/bin/gzip: 4: Syntax error:
Stable Huawei micro certification, stable Huawei cloud database service practice
Stack and queue
Introduction to hashtable
查询mysql数据库中各表记录数大小
关于进程、线程、协程、同步、异步、阻塞、非阻塞、并发、并行、串行的理解
Solve the compilation problem of "c2001: line breaks in constants"
Crawler notes: improve data collection efficiency! Use of proxy pool and thread pool
P3500 [POI2010]TES-Intelligence Test(二分&离线)
10个 Istio 流量管理 最常用的例子,你知道几个?
Mysql数据库慢sql抓取与分析
捷码赋能案例:专业培训、技术支撑,多措并举推动毕业生搭建智慧校园毕设系统
1291_ Add timestamp function in xshell log
[face recognition series] | realize automatic makeup
What is the difference between gateway address and IP address in tcp/ip protocol?
P3033 [usaco11nov]cow steelchase g (similar to minimum path coverage)
MySql數據庫root賬戶無法遠程登陸解决辦法
[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
2328. 网格图中递增路径的数目(记忆化搜索)