概述
后续知识会进行整理
代码
/** echo server
* Time: 2021-12-02
* Author: LH
* code: --utf8--
*/
#ifdef ____Win32
#else
/* network io */
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <poll.h>
/* linux */
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
/* C */
#include <string.h>
#include <stdio.h>
#define SERVERPORT 3119
int main() {
/** Create listening sockets
*/
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd == -1) {
printf("socket error n");
return -1;
}
/* Set reuse IP and port number */
int on = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on));
/* Set feizuse */
int oldSocketFlag = fcntl(listenfd, F_GETFL, 0);
int newSocketFlag = oldSocketFlag | O_NONBLOCK;
if (fcntl(listenfd, F_SETFL, newSocketFlag) == -1) {
close(listenfd);
printf("fcntl error n");
return -1;
}
/* Initializing the server */
struct sockaddr_in bindaddr;
bindaddr.sin_family = AF_INET;
bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bindaddr.sin_port = htons(SERVERPORT);
if (bind(listenfd, (struct sockaddr *) &bindaddr, sizeof(bindaddr)) == -1) {
printf("bind error n");
close(listenfd);
return -1;
}
/* Start Listening */
if (listen(listenfd, SOMAXCONN) == -1) {
printf("listen error n");
close(listenfd);
return -1;
}
/* create epoll */
int epollfd = epoll_create(1);
if (epollfd == -1) {
printf("epoll_create error n");
close(listenfd);
return -1;
}
/** struct epoll_event {
* uint32_t events; fd event flags to be monitored
* epoll_data_t data; User-defined data
* }
* typedef union epoll_data {
* void *prt;
* int fd;
* uint32_t u32;
* uint64_t u64;
* }
*/
struct epoll_event listen_fd_event;
listen_fd_event.data.fd = listenfd;
listen_fd_event.events = EPOLLIN;
/**The default is LT mode,
* where a fixed number of bytes are charged at once according to the
* service until they are collected */
/**ET mode, when the readable event is triggered, the data on the
* socket must be collected at once to feel, must be the village to
* call the recv function until the recv error, the error code is EWOULDBLOCK
*/
// listen_fd_event.events |= EPOLLET; /* start ET */
/* Bind the listening socket to epollfd */
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &listen_fd_event) == -1) {
printf("epoll_ctl error n");
close(listenfd);
return -1;
}
int n;
while(1) {
struct epoll_event epoll_events[1024];
/* Returns the number of fd's with time */
n = epoll_wait(epollfd, epoll_events, 1024, 1000);
if (n < 0) {
/* Interrupted by signal */
if (errno == EINTR)
continue;
break;
}
else if (n == 0) {
/* Timeout, continue */
continue;
}
for (size_t i = 0; i < n; ++ i) {
/* Event Readable */
if (epoll_events[i].events & EPOLLIN) {
if (epoll_events[i].data.fd == listenfd) {
printf("a new client is connect! n");
/* Listening to sockets and receiving new connections */
struct sockaddr_in clientaddr;
socklen_t clientaddrlen = sizeof(clientaddr);
int clientfd = accept(listenfd,
(struct sockaddr *) &clientaddr,
&clientaddrlen);
if (clientfd != -1) {
/* Set feizuse */
int oldSocketFlag = fcntl(clientfd, F_GETFL, 0);
int newSocketFlag = oldSocketFlag | O_NONBLOCK;
if (fcntl(clientfd, F_SETFL, newSocketFlag) == -1) {
close(clientfd);
printf("set client to nonblocking error n");
}
else {
/** struct epoll_event {
* uint32_t events; fd event flags to be monitored
* epoll_data_t data; User-defined data
* }
*/
struct epoll_event client_fd_event;
client_fd_event.data.fd = clientfd;
/* Listening to both read and write events */
client_fd_event.events = EPOLLIN | EPOLLOUT;
client_fd_event.events |= EPOLLET;
/* Add to epollfd */
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, clientfd, &client_fd_event) != -1) {
// printf("new client accepted, clientfd: %d n", clientfd);
}
else {
printf("add client fd to epollfd error n");
close(clientfd);
}
}
}
}
else {
printf("client fd: %d recv data n", epoll_events[i].data.fd);
char recvbuf[1024] = { 0 };
/* Receive 1 byte at a time */
int m = recv(epoll_events[i].data.fd, &recvbuf, 1024, 0);
if (m == 0) {
/* The other end closes the connection and removes the clienfd from the epollfd */
if (epoll_ctl(epollfd, EPOLL_CTL_DEL, epoll_events[i].data.fd, NULL) != -1) {
printf("client disconnected clientfd: %d n", epoll_events[i].data.fd);
}
close(epoll_events[i].data.fd);
}
else if (m < 0) {
/* error */
if (errno != EWOULDBLOCK && errno != EINTR) {
/* The other end closes the connection and removes the clienfd from the epollfd */
if (epoll_ctl(epollfd, EPOLL_CTL_DEL, epoll_events[i].data.fd, NULL) != -1) {
printf("client disconnected clientfd: %d n", epoll_events[i].data.fd);
}
close(epoll_events[i].data.fd);
}
}
else {
/* normal */
printf("recv from client: %d,%s", epoll_events[i].data.fd, recvbuf);
struct epoll_event client_fd_event;
client_fd_event.data.fd = epoll_events[i].data.fd;
/* Register the writeable event to clientfd again */
/**In ET mode, the writable event will not be triggered all the time,
* he will only trigger once and register again after the trigger is
* completed, and the writable event will continue to trigger only
* when the writable event is monitored. LT is repeatedly triggered
* by writable events. After a writable event is triggered, if it
* is no longer needed, the registration of the writable event should
* be removed immediately
*/
client_fd_event.events = EPOLLIN | EPOLLOUT | EPOLLET;
if (epoll_ctl(epollfd, EPOLL_CTL_MOD, epoll_events[i].data.fd, &client_fd_event) != -1) {
// printf("epoll_ctl successfully, mode: EPOLL_CTL_MOD, clientfd: %d n", epoll_events[i].data.fd);
}
else {
printf("epoll_ctl failure, mode: EPOLL_CTL_MOD, clientfd: %d n", epoll_events[i].data.fd);
}
}
}
}
/* Listening to write events */
else if (epoll_events[i].events & EPOLLOUT) {
/* Handle only write events for client fd */
if (epoll_events[i].data.fd != listenfd) {
/* print result */
// printf("EPOLLOUT Triggered, clientfd: %d n", epoll_events[i].data.fd);
}
}
else if (epoll_events[i].events & EPOLLERR) {
// TODO
printf("epoll error! n");
}
}
}
close(listenfd);
return 0;
}
#endif
测试
> gcc -g -o epoll_server epoll_server.c
> ./epoll_server
a new client is connect!
client fd: 5 recv data
recv from client: 5,asdh
client fd: 5 recv data
recv from client: 5,awqr
> nc -v 127.0.0.1 3119
Connection to 127.0.0.1 3119 port [tcp/*] succeeded!
asdh
awqr
最后
以上就是俭朴小松鼠为你收集整理的一个epoll的ET模式下的非阻塞的服务端小用例的全部内容,希望文章能够帮你解决一个epoll的ET模式下的非阻塞的服务端小用例所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复