当前位置: 首页 > news >正文

epoll编程实例客户端_socket采用epoll编程demo

epoll的结构体

typedef union epoll_data {

void *ptr;

int fd;

uint32_t u32;

uint64_t u64;

} epoll_data_t;

struct epoll_event {

uint32_t events; /* Epoll events */

epoll_data_t data; /* User data variable */

};

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define SERV_PORT 8802

int main()

{

int i,flag;

int sockfd,clntfd,newfd;

int epfd,nfds;

ssize_t n;

char buffer[1024];

int s = sizeof(struct sockaddr);

struct sockaddr_in serv_addr;

struct sockaddr_in clnt_addr;

//定义epoll数据结构

struct epoll_event ev,events[20];

epfd = epoll_create(256);

//创建socket,并初始化事件ev

sockfd = socket(AF_INET, SOCK_STREAM, 0);

if (sockfd < 0) {

perror("socket error!\n");

return -1;

}

ev.data.fd = sockfd;

ev.events = EPOLLIN|EPOLLET;

//注册epoll事件

flag = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);

if (flag < 0) {

perror("epoll_ctl error!\n");

return -1;

}

bzero(&serv_addr, sizeof(serv_addr));

serv_addr.sin_family = AF_INET;

serv_addr.sin_port = htons(SERV_PORT);

serv_addr.sin_addr.s_addr = htonl( INADDR_ANY );

flag = bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(struct sockaddr));

if (flag < 0) {

perror("bind error!\n");

return -1;

}

printf("bind\n");

flag = listen(sockfd, 20);

if (flag < 0) {

perror("listen error!\n");

return -1;

}

printf("listen\n");

//开始循环

while (1) {

//等待事件发生,返回请求数目

nfds = epoll_wait(epfd, events, 20, 500);

//一次处理请求

for (i = 0; i < nfds; ++i) {

if (events[i].data.fd == sockfd){

clntfd = accept(sockfd, (struct sockaddr*)&clnt_addr,(unsigned int*)&s);

if (clntfd < 0) {

perror("accept error");

continue;

}

printf("accept\n");

char *str = inet_ntoa(clnt_addr.sin_addr);

printf("accepnt the client ip : %s\n",str);

//设置文件标识符,设置操作属性:写操作

ev.data.fd = clntfd;

ev.events = EPOLLOUT | EPOLLET;

//向创建的的epoll进行注册写操作

epoll_ctl(epfd, EPOLL_CTL_ADD, clntfd, &ev);

} else if (events[i].events & EPOLLOUT) {

printf("EPOLLOUT\n");

if ((newfd = events[i].data.fd) < 0)

continue;

bzero(buffer,sizeof(buffer));

strcpy(buffer,"welcome to myserver!\n");

flag = send(newfd, buffer, 1024, 0);

if (flag < 0) {

perror("send error");

continue;

}

//修改操作为读操作

ev.data.fd = clntfd;

ev.events = EPOLLIN | EPOLLET;

epoll_ctl(epfd, EPOLL_CTL_MOD, newfd, &ev);

} else if (events[i].events & EPOLLIN) {

printf("EPOLLIN\n");

bzero(buffer,sizeof(buffer));

if ((newfd = events[i].data.fd) < 0)

continue;

if ((n = read(newfd, buffer, 1024)) < 0) {

if (errno == ECONNRESET){

close(newfd);

events[i].data.fd = -1;

printf("errno ECONRESET!\n");

} else {

perror("readbuffer error!\n");

}

} else if (n == 0) {//表示客户端已经关闭

close(newfd);

events[i].data.fd = -1;

printf("n为0\n");

}

if (buffer[0] != '0')

printf("have read: %s\n", buffer);

}

}

}

close(sockfd);

return 0;

}

引自:https://www.bbsmax.com/A/l1dymR3Gde/

优化

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define SERV_PORT 8802

#define MAX_EVENTS 20

int main()

{

int listen_fd = socket(AF_INET, SOCK_STREAM, 0); //若成功则返回非负描述符,若失败则返回-1,第一个参数指明协议族(IPv4或IPv6等)

if (listen_fd < 0) { //第二个参数指明套接字类型,字节流套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM)

perror("socket error!\n");

return -1;

}

int epfd = epoll_create(256); //参数会被忽略,但是要大于0,

//若成功返回一个大于 0 的值,表示 epoll 实例;若返回 -1 表示出错

//针对监听的sockfd,创建epollevent

struct epoll_event event;

event.data.fd = listen_fd;

event.events = EPOLLIN | EPOLLET;

//注册epoll事件

int flag = epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &event); //int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

if (flag < 0) { //成功返回0,出错返回-1

perror("epoll_ctl error!\n");

return -1;

}

if (bindAndListenFd(listen_fd) < 0)

return -1;

//定义epoll数据结构

struct epoll_event events[MAX_EVENTS]; //可以使用vector,参见muduo源码中的使用

while (1) {

//等待事件发生,返回请求数目

int nfds = epoll_wait(epfd, events, MAX_EVENTS, 500); //maxevents: 返回的events的最大个数,如果最大个数大于实际触发的个数,则下次epoll_wait的时候仍然可以返回

//int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

//成功返回的是一个大于 0 的数,表示事件的个数;返回 0 表示的是超时时间到;若出错返回 -1.

for (int i = 0; i < nfds; ++i) {

if (events[i].data.fd == listen_fd) {

struct sockaddr_in client_addr;

int client_fd = accept(listen_fd, (struct sockaddr*)&client_addr, sizeof(client_addr)); //若成功则为非负描述符,若出错则返回-1

if (client_fd < 0) {

perror("accept error");

continue;

}

char *str = inet_ntoa(client_addr.sin_addr);

printf("accept the client ip : %s\n",str);

onRecvNewConnect(epfd, client_fd);

} else if (events[i].events & EPOLLOUT) {

int sockfd = events[i].data.fd;

if (sockfd < 0)

continue;

onWriteFd(epfd, sockfd);

} else if (events[i].events & EPOLLIN) {

int sockfd = events[i].data.fd;

if (sockfd < 0)

continue;

if (onReadFd(epfd, sockfd) < 0) {

events[i].data.fd = -1;

}

}

}

}

close(sockfd);

return 0;

}

int bindAndListenFd(int sockfd) {

::fcntl(sockfd, F_SETFL, O_NONBLOCK); //设置非阻塞模式

struct sockaddr_in serv_addr;

bzero(&serv_addr, sizeof(serv_addr)); //void bzero(void *dest, size_t nbytes);

serv_addr.sin_family = AF_INET; //类似void *memset(void *dest, int c, size_t len);

serv_addr.sin_port = htons(SERV_PORT); //本地端口号转化为网络端口号 host to network short

serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY代表本机所有的IP地址 host to network long

int flag = bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); //成功返回0,出错返回-1

if (flag < 0) {

perror("bind error!\n");

return -1;

}

flag = listen(sockfd, 20); //成功返回0,出错返回-1

if (flag < 0) {

perror("listen error!\n");

return -1;

}

return 0;

}

void onRecvNewConnect(int epfd, int clientfd) {

::fcntl(sockfd, F_SETFL, O_NONBLOCK); //设置非阻塞模式

//设置文件标识符,设置操作属性:写操作

struct epoll_event ev_client;

ev_client.data.fd = clintfd;

ev_client.events = EPOLLOUT | EPOLLET;

//向创建的的epoll进行注册写操作

epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &ev_client);

}

void onWriteFd(int epfd, int sockfd) {

char buffer[1024];

bzero(buffer, sizeof(buffer));

strcpy(buffer, "welcome to myserver!\n");

int flag = send(sockfd, buffer, 1024, 0);

if (flag < 0) {

perror("send error");

return;

}

//修改操作为读操作

struct epoll_event ev_client;

ev_client.data.fd = sockfd;

ev_client.events = EPOLLIN | EPOLLET;

epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev_client);

}

int onReadFd(int epfd, int sockfd) {

char buffer[1024];

bzero(buffer, sizeof(buffer));

int n = read(sockfd, buffer, 1024);

if (n < 0) {

if (errno == ECONNRESET) {

close(sockfd);

printf("errno ECONRESET!\n");

return -1;

} else {

perror("readbuffer error!\n");

}

} else if (n == 0) { //表示客户端已经关闭

close(sockfd);

printf("n为0\n");

return -1;

}

if (buffer[0] != '0')

printf("have read: %s\n", buffer);

return 0;

}

相关文章:

  • pythonsvd内存不足_python – 有没有办法防止numpy.linalg.svd内存不足?
  • python 统计分析apache日志_Apache 日志分析(一)
  • mysql中groupby会用到索引吗_MySQL优化GROUP BY方案
  • php5.6的apaches的dll_win7(64位)php5.6-Apache2.4-mysql5.6环境安装
  • freemarker反向取数_freemarker 取值(插值)(转)
  • miui 谷歌框架_谷歌和高通正式联手,加强安卓系统掌控,华为:鸿蒙正全面超越...
  • python 随机打乱列表_python打乱列表
  • 图片画圈画箭头用什么软件_什么软件可以在编辑图片中画圈圈,如裁图时需要特..._网络编辑_帮考网...
  • 0 win10重装partition_gpt分区无法安装win10的根本原因
  • python csv库下载_Python标准库--csv模块
  • kafka身份认证 maxwell_python – kafka身份验证和授权
  • python类的封装是什么意思_Python中什么是面向对象-封装
  • 瑞银监控机器人组装法_“机器人革命”来了!瑞银计划年内再扩充400台自动化机器人...
  • laravel 控制器中使用中间件_热式气体质量流量控制器在流量监测和气压测试中的使用情况...
  • linux vim 添加注释_【Linux】Vim编辑器-批量注释与反注释
  • 【译】JS基础算法脚本:字符串结尾
  • Hibernate【inverse和cascade属性】知识要点
  • leetcode-27. Remove Element
  • spring + angular 实现导出excel
  • SpringBoot 实战 (三) | 配置文件详解
  • Vue ES6 Jade Scss Webpack Gulp
  • VUE es6技巧写法(持续更新中~~~)
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 收藏好这篇,别再只说“数据劫持”了
  • 数据结构java版之冒泡排序及优化
  • 微信小程序:实现悬浮返回和分享按钮
  • 项目实战-Api的解决方案
  • 小程序上传图片到七牛云(支持多张上传,预览,删除)
  • 原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • 正则学习笔记
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • scrapy中间件源码分析及常用中间件大全
  • #Lua:Lua调用C++生成的DLL库
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • $.ajax,axios,fetch三种ajax请求的区别
  • (1)Android开发优化---------UI优化
  • (10)STL算法之搜索(二) 二分查找
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (11)MATLAB PCA+SVM 人脸识别
  • (C语言)输入一个序列,判断是否为奇偶交叉数
  • (NSDate) 时间 (time )比较
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (简单) HDU 2612 Find a way,BFS。
  • (三) prometheus + grafana + alertmanager 配置Redis监控
  • (一)RocketMQ初步认识
  • (转)Google的Objective-C编码规范
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • .NET delegate 委托 、 Event 事件,接口回调
  • .NET委托:一个关于C#的睡前故事
  • .NET学习教程二——.net基础定义+VS常用设置
  • .net与java建立WebService再互相调用
  • @html.ActionLink的几种参数格式