一.服务端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <errno.h>
#define PORT 9190
#define BUFFER_SIZE 1024
#define EPOLL_SIZE 1024// epoll文件描述符和epoll_wait()返回事件集合
struct event_loop {int ep_fd;struct epoll_event events[EPOLL_SIZE];
};struct event_loop *ev_loop = NULL;// 事件
struct event_item{int sock_fd;                                              //  事件的文件描述符int (*callback)(int sock_fd, int event, void *arg);       //  事件响应回调函数char send_buffer[BUFFER_SIZE];                            //  事件发送缓冲区char receive_buffer[BUFFER_SIZE];                         //  事件接收缓冲区ssize_t str_len;                                          //  接收缓冲区可读长度
};// 错误处理
void error_handler(const char *message);
// 回调函数
int accept_callback(int sock_fd, int event, void *arg);     // 坚挺套接字对应回调函数
int receive_callback(int sock_fd, int event, void *arg);    // 可接收数据套接字回调函数
int send_callback(int sock_fd, int event, void *arg);       // 可发送数据套接字回调函数int main() {int server_sock;server_sock = socket(AF_INET, SOCK_STREAM, 0);if (server_sock == -1) {error_handler("socket() error");}struct sockaddr_in server_address;bzero(&server_address, sizeof(server_address));server_address.sin_family = AF_INET;server_address.sin_addr.s_addr = htonl(INADDR_ANY);server_address.sin_port = htons(PORT);if (bind(server_sock, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) {error_handler("bind() error");}if (listen(server_sock, 5) == -1) {error_handler("listen() error");}// epoll_creat()ev_loop = (struct event_loop *) malloc(sizeof(struct event_loop));ev_loop->ep_fd = epoll_create(EPOLL_SIZE);// 监听事件初始化struct epoll_event event;event.data.fd = server_sock;event.events = EPOLLIN;struct event_item *item = (struct event_item *)malloc(sizeof(struct event_item));item->sock_fd = server_sock;item->callback = accept_callback;event.data.ptr = item;// 向epoll()注册监听套接字事件epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_ADD, server_sock, &event);while (1) {int ep_cnt = epoll_wait(ev_loop->ep_fd, ev_loop->events, EPOLL_SIZE, -1);if (ep_cnt < 0) {break;}for (int i = 0; i < ep_cnt; i++) {if (ev_loop->events[i].events & EPOLLIN) {// 可接受数据事件(监听套接字,可recv()数据套接字)struct event_item *s = ev_loop->events[i].data.ptr;s->callback(s->sock_fd, ev_loop->events[i].events, s);}if (ev_loop->events[i].events & EPOLLOUT) {// 可发送数据事件struct event_item *s = ev_loop->events[i].data.ptr;s->callback(s->sock_fd, ev_loop->events[i].events, s);}}}return 0;
}void error_handler(const char *message) {fputs(message, stderr);fputc('\n', stderr);exit(1);
}int accept_callback(int sock_fd, int event, void *arg) {// 接收客户端连接int client_sock;struct sockaddr_in client_address;socklen_t client_address_size = sizeof(client_address);client_sock = accept(sock_fd, (struct sockaddr *)&client_address, &client_address_size);if (client_sock == -1) {return -1;} else {char str[INET_ADDRSTRLEN];printf("new connect from ip: %s port: %d\n", inet_ntop(AF_INET, &client_address.sin_addr.s_addr, str, INET_ADDRSTRLEN),ntohs(client_address.sin_port));}// 注册事件struct epoll_event ev;ev.data.fd = client_sock;ev.events = EPOLLIN;struct event_item *ev_item = (struct event_item *) malloc(sizeof(struct event_item));ev_item->sock_fd = client_sock;ev_item->callback = receive_callback;ev.data.ptr = ev_item;epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_ADD, client_sock, &ev);return 0;
}int receive_callback(int sock_fd, int event, void *arg) {struct event_item *s = (struct event_item *)arg;s->str_len = recv(sock_fd, s->receive_buffer, BUFFER_SIZE, 0);if (s->str_len < 0) {epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_DEL, sock_fd, NULL);close(sock_fd);free(s);return -1;} else if (s->str_len == 0) {epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_DEL, sock_fd, NULL);close(sock_fd);free(s);return 0;} else {// 接收到数据,将监听状态变为可写memcpy(s->send_buffer, s->receive_buffer, s->str_len);struct epoll_event ev;ev.events = EPOLLOUT;ev.data.fd = sock_fd;s->callback = send_callback;ev.data.ptr = s;epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_MOD, sock_fd, &ev);bzero(s->receive_buffer, BUFFER_SIZE);return s->str_len;}
}int send_callback(int sock_fd, int event, void *arg) {// 发送完成,将事件变为可读struct event_item *s = (struct event_item *)arg;send(sock_fd, s->send_buffer, s->str_len, 0);bzero(s->send_buffer, BUFFER_SIZE);struct epoll_event ev;ev.data.fd = sock_fd;ev.events = EPOLLIN;s->sock_fd = sock_fd;s->callback = receive_callback;ev.data.ptr = s;epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_MOD, sock_fd, &ev);return 0;
}

单线程Rector实现回声服务器(四)相关推荐

  1. C++回声服务器_3-UDP版本

    这次我们实现一个UDP版本的回声服务器. 用于传输数据的函数 UDP套接字不会像TCP套接字那样保持连接状态,因此每次传输数据都要添加目标地址信息. 用于传输数据的函数: 发送数据到目标服务器. #i ...

  2. 基于epoll实现一个IO多路复用的回声服务器

    任务: 实现一个TCP server的回声服务器,功能是将客户端发送的消息原样返回,应用epoll处理事件循环实现IO多路复用.借此任务理解IO多路复用应用的开发模式. 参考资料: http://ma ...

  3. 简单回声服务器的实现

    文章目录 1 简单回声服务器的实现 1 简单回声服务器的实现 实现非常非常简单,而且没啥实用价值,代码如下: server.c: #include <stdio.h> #include & ...

  4. boost::phoenix模块实现自适应回声服务器相关的测试程序

    boost::phoenix模块实现自适应回声服务器相关的测试程序 实现功能 C++实现代码 实现功能 boost::phoenix模块实现自适应回声服务器相关的测试程序 C++实现代码 #inclu ...

  5. epoll边缘触发_C++回声服务器_9-epoll边缘触发模式版本服务器

    epoll默认情况下是水平触发模式,这次将epoll设置为边缘触发模式来实现服务器,而客户端直接使用完美回声服务器的客户端. 服务器代码 #include #include #include #inc ...

  6. 012.成型版回声服务器

    目录 带错误处理的回声服务器的实现 server.cpp client.cpp error_handling.cpp error_handling.h 遇到的问题,自定义函数显示未定义的引用. 问题分 ...

  7. 010.第一个回声服务器可能遇到的问题——connect函数

    目录 由connect函数使用不当导致的小错误 server.c client.c 最终效果: 新server.c:主要用于排错 在回顾connect函数: 完整博客: 由connect函数使用不当导 ...

  8. 008.一个简单的网络服务器开发----回声服务器

    目录 简单的回声服务器实现 项目需求 技术分析 博主相关的技术博客 网络编程之 socket编程 网络编程函数小总结与初识socket 网络编程之bind()的未解之谜 网络编程之 字节序和深入理解b ...

  9. socket编程之回声服务器

    回声服务器的实现 结合我们之前对socket函数的分析,现在做一个最简单的回声服务器(由客户端输入一串字符,再由服务器端转换成大写字符回显给客户端) 特别说明:为了突出代码的逻辑部分,博主就没有在写有 ...

最新文章

  1. idea 亮度 调整_工业设计 | 2019优秀产品设计——IDEA金奖作品
  2. 【动态规划】天上掉馅饼
  3. IIS7配置Gzip压缩
  4. 验证用户名和密码的C语言程序,客户端验证用户名和密码的方法详解
  5. python编程入门第一课_[转载]Python第一课教学设计及反思
  6. 机器学习-29-Pointer Network(指针网络)
  7. 腾达无线路由器连不上服务器,腾达无线路由器中继失败怎么办?
  8. Windows 7/10下安装Ubuntu 16.04双系统
  9. Kali linux 学习笔记(二)环境优化(网络配置、软件安装、显卡优化、线程限制、电源优化) 2020.2.12
  10. 免费思维导图软件,收藏
  11. Flink学习-DataStream-HDFSConnector(StreamingFileSink)
  12. Navicat导出整个数据库(可以直接迁移,不会因为外键关系而导致导入不了)
  13. 微信小程序——页面之间传递值
  14. WSFederation 身份验证模块概述
  15. java+sql+物流快递管理系统
  16. 【Javaee毕业设计】基于JAVA_JSP电子书下载系统
  17. 计算机考试行高怎么设置,2017年职称计算机考试WPS教程:表格行高列宽的调整...
  18. 南京大学地图学与地理信息系统815考研资料
  19. matlab实现曲线积分(path_integral函数)
  20. Win7如何禁用Guest账户?

热门文章

  1. 【2022最新Java面试宝典】—— 设计模式面试题(14道含答案)
  2. 第十课:浅谈web网站
  3. 可以测试真假音的软件,想自由转换真假音,我教你啊!
  4. 校园网显示认证服务器暂不可用请稍后重试,[问题]校园网认证成功却不能上网?...
  5. 新的换脸模型FaceShifter论文解读
  6. 2021CVPR 弱/暗光《Seeing in Extra Darkness Using a Deep-Red Flash》
  7. Oracle查询提示 ORA-00933: SQL command not properly ended 原因排查
  8. 美国防承包商邮件系统遭攻击,军事机密或泄露
  9. 圆壹智慧创始人兼CEO 潘麓蓉:AI制药工业落地的痛点与前进方向
  10. 使用Scala语言编写Spark应用程序实现数据去重