网络编程 IO多路复用 [epoll版] (TCP网络聊天室)

//head.h            头文件

//TcpGrpSer.c     服务器端

//TcpGrpUsr.c     客户端

通过IO多路复用实现服务器在单进程单线程下可以与多个客户端交互

 API

epoll函数

#include<sys/epoll.h>
int epoll_create(int size);
功能:创建一个epoll句柄//创建红黑树根节点
epoll把要监测的事件文件描述符挂载到红黑树上
参数:size 没有意义,但是必须>0
返回值:成功返回根节点对应的文件描述符,失败返回-1int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:实现对于epoll的控制
参数:
epfd:epoll_create创建的句柄
op:控制方式EPOLL_CTL_ADD:添加要监测的事件文件描述符EPOLL_CTL_MOD:修改epoll检测的事件类型EPOLL_CTL_DEL:将文件描述符从epoll删除
fd:要操作的文件描述符
event:事件结构体
typedef union epoll_data {void        *ptr;int          fd;//使用这个uint32_t     u32;uint64_t     u64;} epoll_data_t;struct epoll_event {uint32_t     events; //EPOLLIN(读) EPOLLOUT(写)epoll_data_t data;        /* User data variable */};
返回值:成功返回0,失败返回-1int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
功能:阻塞等待准备好的文件描述符
参数:
epfd:epoll句柄
events:存放就绪事件描述符的结构体数组首地址
maxevents:监听的事件最大个数
timeout:超时检测>0:毫秒级检测==0:立即返回-1:不关心是否超时返回值:
>0:准备好的文件描述符的个数
==0:超时
<0:失败

 head.h

#ifndef __HEAD_H__
#define __HEAD_H__#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<math.h>
#include<errno.h>
#include<fcntl.h>
#include<signal.h>#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/shm.h>
#include<sys/time.h>
#include<sys/sem.h>#include<pthread.h>
#include<semaphore.h>#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/select.h>
#include<poll.h>
#include<sys/epoll.h>
#include<sys/fcntl.h>#define NUM 10
#define ERR_MSG(msg)                    \do                                  \{                                   \printf("line: %d\n", __LINE__); \perror(msg);                    \} while (0)#define PORT 6666			// 端口号的网络字节序  1024~49151
#define IP "192.168.250.100" // ifconfig查看本机IP  (ipv4)#endif

TcpGrpSer.c

#include "head.h"int main(int argc, const char *argv[])
{// 创建流式套接字int sfd = socket(AF_INET, SOCK_STREAM, 0);if (sfd < 0){ERR_MSG("socket");return -1;}// 填充服务器自身的地址信息结构体// 真实的地址信息结构体根据地址族制定AF_INET ;struct sockaddr_in sin;sin.sin_family = AF_INET;			 // 必须填充AF_INETsin.sin_port = htons(PORT);			 // 端口号的网络字节序  1024~49151sin.sin_addr.s_addr = inet_addr(IP); // ifconfig查看本机IPint reuse = 1;if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) // 允许端口快速被重复使用{ERR_MSG("setsockopt");return -1;}// 绑定连接if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0){ERR_MSG("bind");return -1;}printf("bind success\n");// 设置监听if (listen(sfd, 128) < 0){ERR_MSG("listen");return -1;}struct epoll_event event;struct epoll_event events[10]; // 存放就绪事件描述符的数组char buf[128] = {0};// 创建epoll句柄int epfd = epoll_create(1);if (epfd < 0){ERR_MSG("epoll_create");exit(-1);}// 添加准备就绪事件进入epoll;event.events = EPOLLIN; // 读事件event.data.fd = sfd;	// 监听套接字放入列表if (epoll_ctl(epfd, EPOLL_CTL_ADD, sfd, &event) < 0){ERR_MSG("epoll_ctl");exit(-1);}event.events = EPOLLIN; // 读事件event.data.fd = 0;		// 终端输入套接字放入列表if (epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &event) < 0){ERR_MSG("epoll_ctl");exit(-1);}// 监听事件是否发生int s_res = 0;struct sockaddr_in cin;socklen_t len = sizeof(cin);struct sockaddr_in savcin[1024];int flags[1024] = {0};int newfd = -1;ssize_t res = 0;while (1){// 监测文件描述符是否准备就绪// 如果成功,s_res接收返回的事件个数,就绪的事件存储到events数组中s_res = epoll_wait(epfd, events, 10, -1);if (s_res < 0){ERR_MSG("select");return -1;}// 与客户端通信for (int i = 0; i < s_res; i++){if (events[i].events & EPOLLIN){if (events[i].data.fd == sfd){printf("客户端连技事件\n");newfd = accept(sfd, (struct sockaddr *)&cin, &len);if (newfd < 0){perror("accept");return -1;}savcin[newfd] = cin;flags[newfd] = 1;printf("[%s:%d] 客户端连接成功 newfd = %d __%d__ \n",inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd, __LINE__);event.events = EPOLLIN | EPOLLET; // 读事件event.data.fd = newfd;	// 新套接字放入链表if (epoll_ctl(epfd, EPOLL_CTL_ADD, newfd, &event) < 0){ERR_MSG("epoll_ctl");exit(-1);}}else if (0 == events[i].data.fd){printf("触发键盘输入事件\n");int sndfd=-1;res=scanf("%d %s",&sndfd,buf);while(getchar() !=10);if(res!=2){printf("请输入正确数据格式:[fd(4~1023)] string\n");continue;}//判断文件是否合法if(flags[i]){printf("sndfd = %d 是非法文件描述符\n",sndfd);continue;}if(send(sndfd,buf,sizeof(buf),0)<0){ERR_MSG("send");}bzero(buf,sizeof(buf));}else{printf("客户端交互事件\n");// res = scanf("%s", buf);// while (getchar() != 10)res = recv(events[i].data.fd, buf, sizeof(buf), 0);if (res < 0){ERR_MSG("send");return -1;}else if (0 == res){printf("[%s:%d] 客户端下线 newfd = %d __%d__ \n",inet_ntoa(savcin[i].sin_addr), ntohs(savcin[i].sin_port), events[i].data.fd, __LINE__);close(i); // 关闭文件描述符flags[i] = 0;}printf("[%s:%d] 客户端 newfd = %d : %s, __%d__ \n",inet_ntoa(savcin[i].sin_addr), ntohs(savcin[i].sin_port), events[i].data.fd, buf, __LINE__);}}}}if (close(sfd) < 0){ERR_MSG("close");return -1;}return 0;
}

TcpGrpUsr.c

#include "head.h"int main(int argc, const char *argv[])
{//创建流式套接字int sfd = socket(AF_INET,SOCK_STREAM,0);if(sfd<0){ERR_MSG("socket");return -1;}int reuse = 1;if(setsockopt(sfd, SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) < 0) //允许端口快速被重复使用{ERR_MSG("setsockopt");return -1;}//填充服务器自身的地址信息结构体//真实的地址信息结构体根据地址族制定AF_INET ; man 7 ipstruct sockaddr_in sin; sin.sin_family      = AF_INET;            //必须填充AF_INETsin.sin_port        = htons(PORT);        //端口号的网络字节序  1024~49151sin.sin_addr.s_addr = inet_addr(IP);      //ifconfig查看本机IPif(connect(sfd,(struct sockaddr *)&sin,sizeof(sin))<0){perror("connect");return -1;}printf("连接成功\n");//创建集合struct pollfd fds[2];fds[0].fd = 0;fds[0].events = POLLIN;fds[1].fd = sfd;fds[1].events = POLLIN;char buf[128]="";int res=0;while(1){//阻塞方式监测集合res = poll(fds,2,-1);if(res < 0){ERR_MSG("poll");return -1;}else if(0 == res){printf("time out...\n");      //超时break;}//判断0文件描述符是否右POLLIN事件if((fds[0].revents & POLLIN)){fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1] = 0;if(send(sfd,buf,sizeof(buf),0) < 0){ERR_MSG("send");return -1;}printf("发送成功\n");}//判断sfd文件描述符是否右POLLIN事件if(fds[1].revents & POLLIN){//接收数据bzero(buf,sizeof(buf));res = recv(sfd,buf,sizeof(buf),0);if(res<0){ERR_MSG("recv");return -1;}else if(res == 0){printf("[%s:%d] 服务器下线__%d__ \n",\inet_ntoa(sin.sin_addr),ntohs(sin.sin_port),__LINE__);break;}printf("[%s:%d] cfd = %d : %s__%d__ \n",\inet_ntoa(sin.sin_addr),ntohs(sin.sin_port),sfd,buf,__LINE__);}	}if(close(sfd)<0){ERR_MSG("close");return -1;}return 0;
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/18985.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

idea如何加快创建Maven项目的速度

一、下载archetype-catalog.xml 下载archetype-catalog.xml的地址 二、配置 以下所说的配置都指全局配置 配置Maven -DarchetypeCataloglocal -Dfile.encodinggbk

线程、进程和管程

一、线程 1.1 定义 线程&#xff1a;线程是进程中的实体&#xff0c;一个进程可以拥有多个线程&#xff0c;一个线程必须有一个父进程。线程有时被称为轻量级进程&#xff0c;是程序执行流的最小单元。 线程的组成部分&#xff1a; 1. 线程ID&#xff1a;线程标识符 2. 当前…

【C++从0到王者】第十五站:list源码分析及手把手教你写一个list

文章目录 一、list源码分析1.分析构造函数2.分析尾插等 二、手把手教你写一个list1.结点声明2.list类的成员变量3.list类的默认构造函数4.list类的尾插5.结点的默认构造函数6.list类的迭代器7.设计const迭代器8.list的insert、erase等接口9.size10.list的clear11.list的析构函数…

SQLserver数据日期数据处理方式(日期查询,日期转换字符串)

获取本月第一天 dateadd(dd,-day(getdate())1,getdate()) 获取下月第一天&#xff08;数据 当前日期减去 日数 在加一个月&#xff09; DATEADD(MM,1,dateadd(dd,-day(getdate())1,getdate())) 获取本月最后一天&#xff08;&#xff09; 将日期转换为字符串的方法两种 1.使用c…

arm neon/fpu/mfloat

neon官网介绍: Arm Neon technology is an advanced Single Instruction Multiple Data (SIMD) architecture extension for the A-profile and R-profile processors. Neon technology is a packed SIMD architecture. Neon registers are considered as vectors of elements …

huatuo(hybridclr)热更新踩坑笔记

个人尝试的结果&#xff0c;不一定为正规的操作&#xff0c;若观者有更好的方案&#xff0c;望赐教。 1.第三方框架应该放在哪里&#xff1f; 以热更框架为例&#xff0c;入口函数进入后&#xff0c;需要调用热更代码检查资源&#xff0c;更新资源&#xff0c;加载程序集。测试…

网络安全 Day25-HTML 介绍和简单基础

HTML 介绍和简单基础 1. HTML 介绍1.1 什么是HTML1.2 如何编辑HTML 2. Html 基础2.1 Html 标题2.2 HTML 段落2.3 HTML 换行2.4 HTML 水平线2.5 HTML 注释2.6 如何查看网页源代码2.7 html标签属性2.8 格式化文字2.9 HTML 实体2.10 HTML 超链接 1. HTML 介绍 1.1 什么是HTML Ht…

前沿分享-会发电的水凝胶敷料

四川大学的研究团队设计了一种新型的伤口敷料&#xff0c; 将电刺激治疗引入伤口敷料&#xff0c;达到营造湿润环境的同时利用电刺激来加速愈合的效果。 上半部分由树状纳米纤维构成&#xff0c;下半部分由双网络导电水凝胶构成&#xff0c;加入了铁离子和儿茶酚。该部分用于贴…

【FPGA IP系列】FIFO的通俗理解

FPGA厂商提供了丰富的IP核&#xff0c;基础性IP核都是可以直接免费调用的&#xff0c;比如FIFO、RAM等等。 本文主要介绍FIFO的一些基础知识&#xff0c;帮助大家能够理解FIFO的基础概念。 一、FIFO介绍 FIFO全称是First In First Out&#xff0c;即先进先出。 FIFO是一个数…

语义检索系统【四】:基于ERNIE-Gram的Pair-wise和基于RocketQA的CrossEncoder训练的单塔模型实现数据精排

搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术细节以及项目实战(含码源) 专栏详细介绍:搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术…

无涯教程-Lua - 环境安装

在Windows上安装 为Windows环境开发了一个单独的名为" SciTE"的IDE,可以从https://code.google.com/p/luaforwindows/下载部分。 运行下载的可执行文件以安装Lua IDE。 由于它是一个IDE&#xff0c;因此您可以使用它来创建和构建Lua代码。 如果您有兴趣在命令行模…

微服务架构的模式介绍

1.微服务架构模式方案 用Scale Cube方法设计应用架构&#xff0c;将应用服务按功能拆分成一组相互协作的服务。每个服务负责一组特定、相关的功能。每个服务可以有自己独立的数据库&#xff0c;从而保证与其他服务解耦。 1.1 聚合器微服务设计模式 聚合器调用多个服务实现应用程…

Jmeter远程服务模式运行时引用csv文件的路径配置

问题 在使用jmeter过程中&#xff0c;本机的内存等配置不足&#xff0c;启动较多的线程时&#xff0c;可以采用分布式运行。 在分布式运行的时候&#xff0c;jmeter会自动将脚本从master主机发送到remote主机上&#xff0c;所以不需要考虑将脚本拷贝到remote主机。但是jmeter…

UPnP是什么?有什么更好的连接方案?快解析内网穿透

一、UPnP是什么 有些小伙伴对于UPnP并不了解&#xff0c;其实UPnP只是一种网络协议&#xff0c;主要作用就是简化家庭和企业网络中设备之间的连接和通信过程&#xff0c;它的主要目标是实现网络的无缝连接&#xff0c;并简化相关网络操作。 二、UPnP有什么主要作用&#xff1…

125.验证回文串

目录 一、题目 二、代码 一、题目 125. 验证回文串 - 力扣&#xff08;LeetCode&#xff09; 二、代码 class Solution { public: bool ABC(char& s) {if (s > 65 && s < 90){s 32;return true;}if (s > 97 && s < 122){return true;}if …

Chapter 10: Dictionaries | Python for Everybody 讲义笔记_En

文章目录 Python for Everybody课程简介DictionariesDictionariesDictionary as a set of countersDictionaries and filesLooping and dictionariesAdvanced text parsingDebuggingGlossary Python for Everybody Exploring Data Using Python 3 Dr. Charles R. Severance 课程…

linux安装Tomcat及部署jpress的详细教程!!!

一、YUM在线安装 1、查看Tomcat相关安装包 [rootlocalhost ~]# yum list | grep tomcat tomcat.noarch 7.0.76-16.el7_9 updates tomcat-admin-webapps.noarch 7.0.76-16.el7_9 updates tomcat-docs…

2D视觉检测算法整理

1.ROI pooling 和 ROI align的区别 ROI pooling第一步根据候选区域找特征图的位置&#xff0c;可能不是刚好对应&#xff0c;需要一次量化&#xff0c;如上图所示&#xff0c;第二次是特征图需要转化为特定的大小&#xff0c;这时候pooling可能也不能正好整除&#xff0c;所以第…

【Linux命令200例】tee将输入内容输出到屏幕和文件

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;本文已收录于专栏&#xff1a;Linux命令大全。 &#x1f3c6;本专栏我们会通过具体的系统的命令讲解加上鲜…

C++ 类型转换 int, hex,char* float, string, wstring

日常的开发中经常会用到类型的相互转换&#xff0c;这里记录一下&#xff1b; 1, int转hex std::string IntToHex(int value) {stringstream ioss;ioss << std::hex << value;string temp;ioss >> temp;return temp;} 2, int转hex 设置宽度 std::string …