原文:

前言

本章节是用基本的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, )|O_NONBLOCK) == -) {
return -;
}
return ;
} int main(int argc, char **argv)
{
int servPort = ;
int listenq = ; int listenfd, connfd, kdpfd, nfds, n, nread, curfds,acceptCount = ;
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) == -)
{
perror("setrlimit error");
return -;
} 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, );
if (listenfd == -) {
perror("can't create socket file");
return -;
} int opt = ;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); if (setnonblocking(listenfd) < ) {
perror("setnonblock error");
} if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) == -)
{
perror("bind error");
return -;
}
if (listen(listenfd, listenq) == -)
{
perror("listen error");
return -;
}
/* 创建 epoll 句柄,把监听 socket 加入到 epoll 集合里 */
kdpfd = epoll_create(MAXEPOLLSIZE);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = listenfd;
if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listenfd, &ev) < )
{
fprintf(stderr, "epoll set insertion error: fd=%d\n", listenfd);
return -;
}
curfds = ; printf("epollserver startup,port %d, max connection is %d, backlog is %d\n", servPort, MAXEPOLLSIZE, listenq); for (;;) {
/* 等待有事件发生 */
nfds = epoll_wait(kdpfd, events, curfds, -);
if (nfds == -)
{
perror("epoll_wait");
continue;
}
/* 处理所有事件 */
for (n = ; n < nfds; ++n)
{
if (events[n].data.fd == listenfd)
{
connfd = accept(listenfd, (struct sockaddr *)&cliaddr,&socklen);
if (connfd < )
{
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) < ) {
perror("setnonblocking error");
}
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = connfd;
if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, connfd, &ev) < )
{
fprintf(stderr, "add socket '%d' to epoll failed: %s\n", connfd, strerror(errno));
return -;
}
curfds++;
continue;
}
// 处理客户端请求
if (handle(events[n].data.fd) < ) {
epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd,&ev);
curfds--; }
}
}
close(listenfd);
return ;
}
int handle(int connfd) {
int nread;
char buf[MAXLINE];
nread = read(connfd, buf, MAXLINE);//读取客户端socket流 if (nread == ) {
printf("client close the connection\n");
close(connfd);
return -;
}
if (nread < ) {
perror("read error");
close(connfd);
return -;
}
write(connfd, buf, nread);//响应客户端
return ;
}

下载地址

编译和启动服务端

gcc epollserver.c -o epollserver
./epollserver

客户端代码

至于客户端可以参考本文的Linux/Unix服务端和客户端Socket编程入门实例的echoclient例子下载编译

Linux IO多路复用之epoll网络编程及源码(转)的更多相关文章

  1. Linux IO多路复用之epoll网络编程(含源码)

    前言 本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下: 客户端从标准输入读入一行,发送到服务端 服务端从网络读取一 ...

  2. Linux IO多路复用之epoll网络编程

    前言 本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下: 客户端从标准输入读入一行,发送到服务端 服务端从网络读取一 ...

  3. 《 UNIX网络编程》源码的使用

    学习编程这东西,看代码,改代码,运行代码这样才能学到实际东西!本书说在www.unpbook.com可以获取源码,不过打不开!所以google unpv13e.tar.gz 并在网络上找到了:源码:h ...

  4. Unix 网络编程卷一源码编译踩坑记录 ubtutu 19.10

    在阅读unpv1时运行源代码的环境配置,这里简单记录一下 源代码里的README 写得挺详细的,但是在Linux 系统的下还没没办法直接编译通过的, 这里我使用的是ubuntu 19.10(在腾讯云1 ...

  5. 【知乎网】Linux IO 多路复用 是什么意思?

    提问一: Linux IO多路复用有 epoll, poll, select,知道epoll性能比其他几者要好.也在网上查了一下这几者的区别,表示没有弄明白. IO多路复用是什么意思,在实际的应用中是 ...

  6. python 网络编程 IO多路复用之epoll

    python网络编程——IO多路复用之epoll 1.内核EPOLL模型讲解     此部分参考http://blog.csdn.net/mango_song/article/details/4264 ...

  7. Java网络编程和NIO详解3:IO模型与Java网络编程模型

    Java网络编程和NIO详解3:IO模型与Java网络编程模型 基本概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32 ...

  8. Linux IO多路复用 poll

    Linux IO多路复用 poll 之前曾经提到过 select poll 跟select类似,poll改进了select的一个确定,就是poll没有监听上限 不过poll还是需要遍历以及频繁的把数组 ...

  9. Linux IO多路复用 select

    Linux IO多路复用 select 之前曾经写过简单的服务器,服务器是用多线程阻塞,客户端每一帧是用非阻塞实现的 后来发现select可以用来多路IO复用,就是说可以把服务器这么多线程放在一个线程 ...

随机推荐

  1. 【译】Kafka最佳实践 / Kafka Best Practices

    本文来自于DataWorks Summit/Hadoop Summit上的<Apache Kafka最佳实践>分享,里面给出了很多关于Kafka的使用心得,非常值得一看,今推荐给大家. 硬 ...

  2. MDK972-EK开发板裸调试设置和裸机程序烧写(转)

    硬件平台:MDK972-EK开发板编译调试软件:KEIL uVision4仿真工具:JLINK V7/V8   本例子从串口输出信息,如图:       KEIL uVision4调试设置如图所示: ...

  3. sqlserver连接问题收集

    问题1. 使用navicat连接本地sqlserver,报错“命名管道提供程序无法打开与 sql server 的连接 [2]” 解决: 参考本篇文章 <持续收集中>

  4. 如何在taro的map循环中使用if条件渲染

    在taro的jsx中,鉴于编译的机制,官方明确的表示了不能在map循环中使用if循环, 但是呢,官方也给出了解决办法,那就是提取变量或者是用三目运算嵌套的方法: 链接奉上:https://github ...

  5. 关于CreateProcess函数一些经验

    TCHAR szCmdLine[]={TEXT("E:\\CPL-server\\其他工具\\restartSrv\\bin\\opensavepath.exe")}; TCHAR ...

  6. Myeclipse10使用git

    用Myeclipse安装egit,使用官网最新地址或者下载最新的egit插件到本地安装均在team中看不到git,最后发现到http://download.eclipse.org/egit/updat ...

  7. 《转》Python学习(19)-python函数(二)-关于lambda

    转自http://www.cnblogs.com/BeginMan/p/3178103.html 一.lambda函数 1.lambda函数基础: lambda函数也叫匿名函数,即,函数没有具体的名称 ...

  8. 【gitlab】创建ssh 秘钥

    1).首先打开linux服务器,输入命令:ls -al ~/.ssh,检查是否显示有id_rsa.pub或者id_dsa.pub存在,如果存在请直接跳至第3步. 2).在bash中输入,注意这个地方的 ...

  9. VIM 如何使用系统的剪切板

    想要将系统剪贴板里的内容复制到 vi 编辑的文档中怎么办? 例如,在网页上复制了一段文字,想贴到本地的某个文件中. 使用 vi 打开本地文件,在 输入 模式下,按 Shift + Insert 详细可 ...

  10. 原生js--userData

    userData是IE5及其以上浏览器支持的一种客户端存储方式,它通过在document元素后面附加一个专属的元素来实现. 对userData的封装: /** * IE userdata封装 */fu ...