Linux IO多路复用之epoll网络编程(含源码)
前言
本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下:
客户端从标准输入读入一行,发送到服务端
服务端从网络读取一行,然后输出到客户端
客户端收到服务端的响应,输出这一行到标准输出
服务端
代码如下:
#include <unistd.h>
#include <sys/types.h> /* basic system data types */
#include <sys/socket.h> /* basic socket definitions */
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <arpa/inet.h> /* inet(3) functions */
#include <sys/epoll.h> /* epoll function */
#include <fcntl.h> /* nonblocking */
#include <sys/resource.h> /*setrlimit */ #include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h> #define MAXEPOLLSIZE 10000
#define MAXLINE 10240
int handle(int connfd);
int setnonblocking(int sockfd)
{
if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1) {
return -1;
}
return 0;
} int main(int argc, char **argv)
{
int servPort = 6888;
int listenq = 1024; int listenfd, connfd, kdpfd, nfds, n, nread, curfds,acceptCount = 0;
struct sockaddr_in servaddr, cliaddr;
socklen_t socklen = sizeof(struct sockaddr_in);
struct epoll_event ev;
struct epoll_event events[MAXEPOLLSIZE];
struct rlimit rt;
char buf[MAXLINE]; /* 设置每个进程允许打开的最大文件数 */
rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;
if (setrlimit(RLIMIT_NOFILE, &rt) == -1)
{
perror("setrlimit error");
return -1;
} bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl (INADDR_ANY);
servaddr.sin_port = htons (servPort); listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd == -1) {
perror("can't create socket file");
return -1;
} int opt = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); if (setnonblocking(listenfd) < 0) {
perror("setnonblock error");
} if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) == -1)
{
perror("bind error");
return -1;
}
if (listen(listenfd, listenq) == -1)
{
perror("listen error");
return -1;
}
/* 创建 epoll 句柄,把监听 socket 加入到 epoll 集合里 */
kdpfd = epoll_create(MAXEPOLLSIZE);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = listenfd;
if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listenfd, &ev) < 0)
{
fprintf(stderr, "epoll set insertion error: fd=%d\n", listenfd);
return -1;
}
curfds = 1; printf("epollserver startup,port %d, max connection is %d, backlog is %d\n", servPort, MAXEPOLLSIZE, listenq); for (;;) {
/* 等待有事件发生 */
nfds = epoll_wait(kdpfd, events, curfds, -1);
if (nfds == -1)
{
perror("epoll_wait");
continue;
}
/* 处理所有事件 */
for (n = 0; n < nfds; ++n)
{
if (events[n].data.fd == listenfd)
{
connfd = accept(listenfd, (struct sockaddr *)&cliaddr,&socklen);
if (connfd < 0)
{
perror("accept error");
continue;
} sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
printf("%d:%s", ++acceptCount, buf); if (curfds >= MAXEPOLLSIZE) {
fprintf(stderr, "too many connection, more than %d\n", MAXEPOLLSIZE);
close(connfd);
continue;
}
if (setnonblocking(connfd) < 0) {
perror("setnonblocking error");
}
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = connfd;
if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, connfd, &ev) < 0)
{
fprintf(stderr, "add socket '%d' to epoll failed: %s\n", connfd, strerror(errno));
return -1;
}
curfds++;
continue;
}
// 处理客户端请求
if (handle(events[n].data.fd) < 0) {
epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd,&ev);
curfds--; }
}
}
close(listenfd);
return 0;
}
int handle(int connfd) {
int nread;
char buf[MAXLINE];
nread = read(connfd, buf, MAXLINE);//读取客户端socket流 if (nread == 0) {
printf("client close the connection\n");
close(connfd);
return -1;
}
if (nread < 0) {
perror("read error");
close(connfd);
return -1;
}
write(connfd, buf, nread);//响应客户端
return 0;
}
下载和编译
编译和启动服务端
gcc epollserver.c -o epollserver
./epollserver
至于客户端可以参考本文的Linux/Unix服务端和客户端Socket编程入门实例的echoclient例子下载编译。
Linux IO多路复用之epoll网络编程(含源码)的更多相关文章
- Linux IO多路复用之epoll网络编程及源码(转)
原文: 前言 本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下: 客户端从标准输入读入一行,发送到服务端 服务端从网 ...
- Linux IO多路复用之epoll网络编程
前言 本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下: 客户端从标准输入读入一行,发送到服务端 服务端从网络读取一 ...
- 《 UNIX网络编程》源码的使用
学习编程这东西,看代码,改代码,运行代码这样才能学到实际东西!本书说在www.unpbook.com可以获取源码,不过打不开!所以google unpv13e.tar.gz 并在网络上找到了:源码:h ...
- Unix 网络编程卷一源码编译踩坑记录 ubtutu 19.10
在阅读unpv1时运行源代码的环境配置,这里简单记录一下 源代码里的README 写得挺详细的,但是在Linux 系统的下还没没办法直接编译通过的, 这里我使用的是ubuntu 19.10(在腾讯云1 ...
- jQuery使用():Callbacks回调函数列表之异步编程(含源码分析)
Callbacks的基本功能回调函数缓存与调用 特定需求模式的Callbacks Callbacks的模拟源码 一.Callbacks的基本功能回调函数缓存与调用 Callbacks即回调函数集合,在 ...
- 【知乎网】Linux IO 多路复用 是什么意思?
提问一: Linux IO多路复用有 epoll, poll, select,知道epoll性能比其他几者要好.也在网上查了一下这几者的区别,表示没有弄明白. IO多路复用是什么意思,在实际的应用中是 ...
- jQuery使用():Deferred有状态的回调列表(含源码)
deferred的功能及其使用 deferred的实现原理及模拟源码 一.deferred的功能及其使用 deferred的底层是基于callbacks实现的,建议再熟悉callbacks的内部机制前 ...
- python 网络编程 IO多路复用之epoll
python网络编程——IO多路复用之epoll 1.内核EPOLL模型讲解 此部分参考http://blog.csdn.net/mango_song/article/details/4264 ...
- Java网络编程和NIO详解3:IO模型与Java网络编程模型
Java网络编程和NIO详解3:IO模型与Java网络编程模型 基本概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32 ...
随机推荐
- [Go]链表的相关知识
切片有着占用内存少喝创建便捷等特点,但它本质上还是数组.切片的一大好处是可以通过窗口快速地定位并获取或者修改底层数组中的元素.不过当删除切片中的元素的时候就没那么简单了.元素复制一般是免不了的,就算只 ...
- 【置换】G. Poker 2.0
https://www.bnuoj.com/v3/contest_show.php?cid=9146#problem/G [题意] 题意很简单,就是“鸽尾式”洗扑克,问洗m次各张牌的位置 [思路] 牌 ...
- iOS React Native 环境的搭建
react native 的官网:http://reactnative.cn/docs/0.47/getting-started.html#content --iOS如何搭建mac版的环境 1.配置 ...
- git修改commit message及vi编辑器的简单使用
1.修改commit信息 git commit --amend 2.进入vi编辑器修改 ‘i’进入insert模式,输入文字: ‘esc’回到命令模式,删除文字,移动光标: ‘:’进入底行模式,‘wq ...
- FatMouse's Speed--hdu1160(dp+输出路径)
Problem Description FatMouse believes that the fatter a mouse is, the faster it runs. To disprove th ...
- Java学习--反码 原码 补码简析
关于课上实验中对小数的处理中出现的问题涉及到原码,反码,补码的问题,所以在网上进行了一下搜索.在原码,反码,补码中的解释可得知,无论是哪一种码,能够表示的数的范围是-2^(位数-1)+1至2^(位数- ...
- win10安装mysql5.6,mysql启动时,闪退
首先在服务中查看是不是mysql启动了 发现在服务中没有mysql服务, 然后找到mysql的安装目录 MYSQL SERVER 5.6 中将my-default.ini 改为my.ini 使用命令行 ...
- how to read openstack code: service plugin
We have learned core plugin, service plugin and extension in last post. Now let`s review: Core Plugi ...
- sklearn特征工程总结
转自: http://www.cnblogs.com/jasonfreak/p/5448385.html https://www.zhihu.com/question/28641663/answer/ ...
- Linux监測某一时刻对外的IP连接情况
相信大家都熟悉netstat命令吧,这里就主要採用此命令.网上流传的DDoS Deflate工具就是採用IP数量来统计对外连接数,然后结合Iptables的方法来实现某个IP增加黑名单和解禁某IP n ...