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

C++基于select和epoll的TCP服务器

select版本

服务器

#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <string>
#include <pthread.h>
#include <sys/select.h>
#include <stdio.h>
int main()
{int flag=0;struct sockaddr_in saddr;saddr.sin_port = htons(8999);saddr.sin_addr.s_addr = INADDR_ANY;saddr.sin_family = AF_INET;int sfd = socket(AF_INET, SOCK_STREAM, 0);if (sfd == -1){perror("socket error");return 1;}int optvalue;setsockopt(sfd, SOL_SOCKET, SO_REUSEPORT, &optvalue,sizeof(int));//设置端口复用flag = bind(sfd, (struct sockaddr*)&saddr, sizeof(struct sockaddr_in));if (flag == -1){perror("bind error");return 1;}flag=listen(sfd, 100);if(flag==-1){perror("listen error");return 1;}fd_set readset,tmp;FD_ZERO(&readset);FD_SET(sfd,&readset);int nfds=sfd;while (1){tmp=readset;//每一次tmp的值都会被内核修改,所以要用readset重制flag=select(nfds+1,&tmp,NULL,NULL,NULL);//异常和写集合一般不检测if(flag==-1){perror("select error");continue;}for(int i=sfd;i<=nfds;i++)//i可以从0开始,但是会做几次多余判断{int port;if(i==sfd&&FD_ISSET(i,&tmp))//判断监听套接字是否满足条件{struct sockaddr_in caddr;int clen=sizeof(caddr);int cfd = accept(sfd, (struct sockaddr*)&caddr, (socklen_t*)&clen);port=ntohs(caddr.sin_port);if (cfd == -1){perror("accept error");continue;}char ip[1024]={'\0'};//必须加上,不然解析IP会失败printf("接收到了客户端%s:%d的连接\n",inet_ntop(AF_INET,&caddr.sin_addr,ip,1024),port);FD_SET(cfd,&readset);//将通信套接字加入文件描述符表nfds=nfds>cfd?nfds:cfd;//更新ndfs}else//判断是否有满足条件的通信套接字{if(FD_ISSET(i,&tmp)){char buf[1024] = {'\0'};flag = recv(i, buf, 1024, 0);if (flag==-1){perror("read error");break;}else if(flag==0){printf("连接断开\n");FD_CLR(i,&readset);close(i);}else{printf("从客户端收到数据:%s\n",buf);std::string sendstr="服务器收到了"+std::to_string(port)+"的数据";flag = send(i, sendstr.c_str(), sendstr.length(), 0);if (flag == -1){perror("send error");}memset(buf, 0, 1024);}}}}}close(sfd);return 0;
}

客户端

#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <string>int main()
{int flag;struct sockaddr_in* caddr=(struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));inet_pton(AF_INET, "192.168.101.231", &caddr->sin_addr.s_addr);caddr->sin_family = AF_INET;caddr->sin_port = htons(8999);int cfd = socket(AF_INET, SOCK_STREAM, 0);if (cfd == -1){perror("socket error");return 1;}int addrlen=sizeof(struct sockaddr);int i=0;flag= connect(cfd, (struct sockaddr*)caddr, addrlen);//caddr就是指针类型if (flag == -1){perror("connect error");return 1;}while(1){char buf[1024] = {'\0'};std::string sendstr="我是客户端"+std::to_string(getpid())+"发送了数据"+std::to_string(i);flag = send(cfd,  sendstr.c_str(), sendstr.length(),0);if (flag == -1){perror("send error");continue;}printf("send:%s\n", sendstr.c_str());flag = recv(cfd, buf, 1024, 0);if (flag == -1){perror("recv error");continue;}printf("客户端收到数据:%s\n", buf);memset(buf, 0, 1024);i++;sleep(1);}close(cfd);return 0;
}

epoll

服务器

int main()
{int flag=0;struct sockaddr_in saddr;saddr.sin_port = htons(8999);saddr.sin_addr.s_addr = INADDR_ANY;saddr.sin_family = AF_INET;int sfd = socket(AF_INET, SOCK_STREAM, 0);if (sfd == -1){perror("socket error");return 1;}int optvalue;setsockopt(sfd, SOL_SOCKET, SO_REUSEPORT, &optvalue,sizeof(int));//设置端口复用flag = bind(sfd, (struct sockaddr*)&saddr, sizeof(struct sockaddr_in));if (flag == -1){perror("bind error");return 1;}flag=listen(sfd, 100);if(flag==-1){perror("listen error");return 1;}int epfd=epoll_create(1);struct epoll_event ev;ev.data.fd=sfd;ev.events=EPOLLIN;flag=epoll_ctl(epfd,EPOLL_CTL_ADD,sfd,&ev);struct epoll_event revents[1024];while (1){int num=epoll_wait(epfd,revents,1024,-1);if(num==-1){perror("epoll wait error");continue;}for(int i=0;i<num;i++){int port;int curfd=revents[i].data.fd;if(curfd==sfd)//判断监听套接字是否满足条件{struct sockaddr_in caddr;int clen=sizeof(caddr);int cfd = accept(sfd, (struct sockaddr*)&caddr, (socklen_t*)&clen);port=ntohs(caddr.sin_port);if (cfd == -1){perror("accept error");continue;}char ip[1024]={'\0'};//必须加上,不然解析IP会失败printf("接收到了客户端%s:%d的连接\n",inet_ntop(AF_INET,&caddr.sin_addr,ip,1024),port);ev.data.fd=cfd;ev.events=EPOLLIN;epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&ev);}else//判断是否有满足条件的通信套接字{char buf[1024] = {'\0'};flag = recv(curfd, buf, 1024, 0);if (flag==-1){perror("recv error");break;}else if(flag==0){printf("连接断开\n");epoll_ctl(epfd,EPOLL_CTL_DEL,curfd,NULL);close(curfd);}else{printf("从客户端收到数据:%s\n",buf);std::string sendstr="服务器收到了"+std::to_string(port)+"的数据";flag = send(curfd, sendstr.c_str(), sendstr.length(), 0);if (flag == -1){perror("send error");}memset(buf, 0, 1024);}}}}close(sfd);return 0;
}

http://www.lryc.cn/news/440493.html

相关文章:

  • SpringBoot 读取配置文件的4种方式
  • 【车载开发系列】ParaSoft单元测试环境配置(三)
  • 如何让Threejs的canvas背景透明?
  • Text-to-SQL技术升级 - 阿里云OpenSearch-SQL在BIRD榜单夺冠方法
  • [性能]高速收发的TCP/MQTT通信
  • OpenHarmony(鸿蒙南向开发)——标准系统方案之瑞芯微RK3568移植案例(下)
  • 网络安全学习(五)Burpsuite实战
  • ego-planner开源代码之simulator.xml介绍分析
  • 论文阅读笔记 --- 图模互补:知识图谱与大模型融合综述 --- 按参考文献整理
  • Cpp类和对象(上)(3)
  • 【微信小程序】连续拍照功能实现
  • JavaSE:11、内部类
  • VTD激光雷达(7)——07_OptiX_Variables_Advanced
  • 运维工程师面试整理-自动化运维
  • 【JAVA基础】实现Tomcat基本功能
  • 风力发电叶片缺陷检测数据集
  • 数据类型自动转换的解决方案
  • 大厂校招:唯品会Java面试题及参考答案
  • Qt常用控件——QLCDNumber
  • 专业学习|GERT网络概览(学习资源、原理介绍、变体介绍)
  • 搭建一个基于角色的权限验证框架
  • 下载chromedriver驱动
  • 在STM32工程中使用Mavlink与飞控通信
  • 【Elasticsearch】-7.17.24版本接入
  • ShouldSniffAttr在自动化测试中具体是如何应用?
  • 前端vue3打印,多页打印,不使用插件(工作中让我写一个打印功能)
  • 传感技术是如何实现实时监测和控制的呢
  • 为什么mac打不开rar文件 苹果电脑打不开rar压缩文件怎么办
  • linux下日志系统setvbuf接口及结构体 handle_file_t成员介绍
  • ESP8266+httpServer+GET+POST实现网页验证密码