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

0915,SOCKET网络编程部分,三种I/O多路复用模型(select ,poll,epoll)

目录   nc 127.0.0.1 port

01_socket_client.cc

01_socket_server.cc

02_select_client.cc

02_select_server.cc

03_poll_server.cc

04_epoll_server.cc

01_socket_client.cc

#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <error.h>
#include <error.h>#include <iostream>
#include <string>using std::cout;
using std::endl;
using std::string;int main(int argc,char** argv)
{//socket-->listenfdint listenfd=socket(AF_INET,SOCK_STREAM,0);if(listenfd<0){error(1,errno,"socket");}//sockaddr_in --> connectstruct sockaddr_in seraddr;memset(&seraddr,0,sizeof(seraddr));seraddr.sin_family=AF_INET;seraddr.sin_port=htons(atoi(argv[2]));//portseraddr.sin_addr.s_addr=inet_addr(argv[1]);//ipint ret=connect(listenfd,(struct sockaddr*)&seraddr,sizeof(seraddr));if(ret<0){error(1,errno,"connect");}//三次握手建立成功while(1){cout<<"propose send message to server"<<endl;string line;getline(std::cin,line);ret=send(listenfd,line.data(),line.size(),0);if(ret<0){cout<<"send error"<<endl;}else if(ret==0){cout<<"ret==0"<<endl;}else{cout<<"send sucessfully"<<endl;}char buff[128]={0};ret=recv(listenfd,buff,sizeof(buff),0);if(ret<0){cout<<"recv error"<<endl;}else if(ret==0){cout<<"ret==0"<<endl;}else{cout<<"recv sucessfully>>>"<<buff<<endl;}}close(listenfd);return 0;
}

01_socket_server.cc

#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <error.h>
#include <error.h>#include <iostream>
#include <string>using std::cout;
using std::endl;
using std::string;int main(int argc,char** argv)
{int listenfd=socket(AF_INET,SOCK_STREAM,0);if(listenfd<0){error(1,errno,"socket");}//port ip 复用int opt=1;int retval=setsockopt(listenfd,SOL_SOCKET,SO_REUSEPORT,&opt,sizeof(opt));if(retval<0){error(1,errno,"setscockopt");}int opt2=1;retval=setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt2,sizeof(opt2));if(retval<0){error(1,errno,"setscockopt2");}//bindstruct sockaddr_in seraddr;memset(&seraddr,0,sizeof(seraddr));seraddr.sin_addr.s_addr=inet_addr(argv[1]);seraddr.sin_port=htons(atoi(argv[2]));seraddr.sin_family=AF_INET;int ret=bind(listenfd,(struct sockaddr*)&seraddr,sizeof(seraddr));if(ret<0){error(1,errno,"bind");}//监听ret=listen(listenfd,128);if(ret<0){error(1,errno,"listen");}cout<<"server is listen"<<endl;//从listenfd队列中取下一个peerfdint connfd=accept(listenfd,nullptr,nullptr);if(connfd<0){error(1,errno,"accept");}//三次握手建立成功while(1){char buff[128]={0};ret=recv(connfd,buff,sizeof(buff),0);if(ret<0){cout<<"recv error"<<endl;}else if(ret==0){cout<<"ret==0"<<endl;}else{cout<<"recv sucessfully>>>"<<buff<<endl;}cout<<"propose send message to client"<<endl;string line;getline(std::cin,line);int ret1=send(connfd,line.data(),line.size(),0);if(ret1<0){cout<<"send error"<<endl;}else if(ret1==0){cout<<"ret1==0"<<endl;}else{cout<<"send sucessfully"<<endl;}}close(listenfd);close(connfd);return 0;
}

02_select_client.cc

#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <error.h>
#include <error.h>#include <iostream>
#include <string>#define SERV_IP "192.168.235.128"
#define SERV_PORT 8000using std::cout;
using std::endl;
using std::string;int main(int argc,char** argv)
{//socket-->listenfdint listenfd=socket(AF_INET,SOCK_STREAM,0);if(listenfd<0){error(1,errno,"socket");}//sockaddr_in --> connectstruct sockaddr_in seraddr;memset(&seraddr,0,sizeof(seraddr));seraddr.sin_family=AF_INET;seraddr.sin_port=htons(SERV_PORT);//port/* seraddr.sin_addr.s_addr=inet_addr(SERV_IP);//ip *//* inet_pton(listenfd, SERV_IP, &serv_addr.sin_addr.s_addr); */seraddr.sin_addr.s_addr=htonl(INADDR_ANY);//服务器绑定所有可用接口int ret=connect(listenfd,(struct sockaddr*)&seraddr,sizeof(seraddr));if(ret<0){error(1,errno,"connect");}//三次握手建立成功char buff[BUFSIZ];//标准io操作的缓冲区大小int nByte;while(1){fgets(buff,sizeof(buff),stdin);//helloc-->hello\n\0write(listenfd,buff,strlen(buff));//buff有效长度//buff的内容写入listenfd(套接字本质文件描述符)nByte=read(listenfd,buff,sizeof(buff));//读取服务器的响应,nByte实际读取的字节数write(STDOUT_FILENO,buff,nByte);//写到stdout}close(listenfd);return 0;
}

02_select_server.cc

#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <error.h>
#include <error.h>
#include <sys/select.h>
#include <sys/time.h>#include <iostream>
#include <string>#define SERV_PORT 8000using std::cout;
using std::endl;
using std::string;int main(int argc,char** argv)
{int cnt ;//debugint connfd,sockfd;int listenfd=socket(AF_INET,SOCK_STREAM,0);if(listenfd<0){error(1,errno,"socket");}//port ip 复用int opt=1;int retval=setsockopt(listenfd,SOL_SOCKET,SO_REUSEPORT,&opt,sizeof(opt));if(retval<0){error(1,errno,"setscockopt");}int opt2=1;retval=setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt2,sizeof(opt2));if(retval<0){error(1,errno,"setscockopt2");}//bindstruct sockaddr_in seraddr;bzero(&seraddr,sizeof(seraddr));/* memset(&seraddr,0,sizeof(seraddr)); */seraddr.sin_addr.s_addr=htonl(INADDR_ANY);seraddr.sin_port=htons(SERV_PORT);seraddr.sin_family=AF_INET;int ret=bind(listenfd,(struct sockaddr*)&seraddr,sizeof(seraddr));if(ret<0){error(1,errno,"bind");}//监听ret=listen(listenfd,128);if(ret<0){error(1,errno,"listen");}cout<<"server is listen"<<endl;//三次握手建立成功char buff[BUFSIZ],str[BUFSIZ];int maxfd=listenfd;int maxi=-1;fd_set rset,allset;int client[FD_SETSIZE];//多1024,可以监视的最大文件描述符数量//定义在/usr/include/linux/posix_types.hfor(int i=0;i<FD_SETSIZE;++i){client[i]=-1;}FD_ZERO(&allset);FD_SET(listenfd,&allset);while(1){rset=allset;int nready=select(maxfd+1,&rset,NULL,NULL,NULL);//nready就绪的描述符数量if(nready<0){error(1,errno,"select");}//01,监听到listenfd 新的链接进来if(FD_ISSET(listenfd,&rset)){struct sockaddr_in clie_addr;socklen_t clie_addr_len=sizeof(clie_addr);//新连接的套接字connfd=accept(listenfd,(struct sockaddr*)&clie_addr,&clie_addr_len);if(connfd==-1){error(1,errno,"accept");}printf("receive from %s : %d\n",inet_ntop(AF_FILE,&clie_addr.sin_addr,str,sizeof(str)),ntohs(clie_addr.sin_port));//三次握手成功int i;for(i=0;i<FD_SETSIZE;++i){if(client[i]<0){client[i]=connfd;break;//加入监听数组} }//==============================cout<<cnt++<<"  "<<i<<endl;if(i==FD_SETSIZE){fputs("too much client\n",stderr);exit(1);}FD_SET(connfd,&allset);//添加新连接//更新maxi,maxfdif(connfd>maxfd){maxfd=connfd;}if(i>maxi){maxi=i;}//如果nready=1.继续while循环,不用走下面的for循环if(--nready==0){continue;}}//02遍历client数组,元素为正,被监听到//是老连接,可以进行数据发送接受for(int i=0;i<=maxi;++i){//caution:i<=maxiif((sockfd=client[i])<0){continue;}
//==============================cout<<cnt++<<"  "<<sockfd<<endl;if(FD_ISSET(sockfd,&rset)){int nByte=read(sockfd,buff,sizeof(buff));if(nByte==0){//数据读完了,(缓冲区没有数据//连接要断开了close(sockfd);cout<<"client "<<sockfd<<" closed connection\n"<<endl;FD_CLR(sockfd,&allset);client[i]=-1;}else if(nByte>0){for(int j=0;j<nByte;++j){buff[j]=toupper(buff[j]);//a->A}write(sockfd,buff,nByte);write(STDOUT_FILENO,buff,nByte);}if(--nready==0){break;}}}}close(listenfd);close(connfd);return 0;
}

03_poll_server.cc

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <error.h>
#include <errno.h>
#include <poll.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>#include <iostream>
#include <string>#define OPEN_MAX 1024
/* #define SERV_IP "192.168.235.128" */
#define SERV_IP "127.0.0.1"
#define SERV_PORT 7888using std::cout;
using std::endl;
using std::string;/* struct pollfd */
/* { */
/*     int   fd;       //要监听的文件描述符 */
/*     short events;   //待监听的文件描述符的事件 POLLIN/POLLOUT/POLLERR */
/*     short revents;  //revents & POLLIN */
/* }; */int main(int argc,char** argv)
{int cnt ;//debugint connfd,sockfd;int listenfd=socket(AF_INET,SOCK_STREAM,0);if(listenfd<0){error(1,errno,"socket");}//port ip 复用int opt=1;int retval=setsockopt(listenfd,SOL_SOCKET,SO_REUSEPORT,&opt,sizeof(opt));if(retval<0){error(1,errno,"setscockopt");}int opt2=1;retval=setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt2,sizeof(opt2));if(retval<0){error(1,errno,"setscockopt2");}//bindstruct sockaddr_in seraddr;bzero(&seraddr,sizeof(seraddr));/* memset(&seraddr,0,sizeof(seraddr)); */seraddr.sin_addr.s_addr=htonl(INADDR_ANY);/* seraddr.sin_addr.s_addr=inet_pton( *//*        listenfd, SERV_IP, &seraddr.sin_addr.s_addr); */seraddr.sin_port=htons(SERV_PORT);seraddr.sin_family=AF_INET;int ret=bind(listenfd,(struct sockaddr*)&seraddr,sizeof(seraddr));if(ret<0){error(1,errno,"bind");}//监听ret=listen(listenfd,128);if(ret<0){error(1,errno,"listen");}cout<<"server is listen"<<endl;//三次握手建立成功char buff[BUFSIZ],str[INET_ADDRSTRLEN];//IPV4地址的字符串表示形式的最大长度int maxi=0;struct pollfd client[OPEN_MAX];//FOPEN_MAX:一个程序可以同时打开的最大文件流数量//poll类型,listenfd加入监听client[0].fd=listenfd;client[0].events=POLLIN;for(int i=1;i<OPEN_MAX;++i){//i=0,会把listenfd删掉,注意初始化顺序client[i].fd=-1;}while(1){int nready=poll(client,maxi+1,-1);if(nready<0){error(1,errno,"select");}
//==============================cout<<cnt++<<"  "<<client[0].fd<<endl;//01,监听到listenfd 新的链接进来if(client[0].revents & POLLIN){struct sockaddr_in clie_addr;socklen_t clie_addr_len=sizeof(clie_addr);//新连接的套接字connfd=accept(listenfd,(struct sockaddr*)&clie_addr,&clie_addr_len);if(connfd==-1){error(1,errno,"accept");}printf("receive from %s : %d\n",inet_ntop(AF_FILE,&clie_addr.sin_addr,str,sizeof(str)),ntohs(clie_addr.sin_port));//三次握手成功int i;for(i=1;i<OPEN_MAX;++i){if(client[i].fd<0){client[i].fd=connfd;break;//加入监听数组} }client[i].events=POLLIN;//设置要监听的类型if(i==OPEN_MAX){fputs("too much client\n",stderr);exit(1);}//更新maxi,fd有新增if(i>maxi){maxi=i;}//如果nready=1.继续while循环,不用走下面的for循环if(--nready==0){continue;}}//02遍历client数组,元素为正,被监听到//是老连接,可以进行数据发送接受for(int i=0;i<=maxi;++i){//caution:i<=maxiif((sockfd=client[i].fd)<0){continue;}//老连接上有数据if(client[i].revents & POLLIN){int nByte=read(sockfd,buff,sizeof(buff));if(nByte<0){if(errno==ECONNRESET){//客户端被强制关闭cout<<"client ["<<i<<"] abort connect"<<endl;close(sockfd);client[i].fd=-1;}else{perror("read nByte=0 error");}}else if(nByte>0){for(int j=0;j<nByte;++j){buff[j]=toupper(buff[j]);//a->A}write(sockfd,buff,nByte);write(STDOUT_FILENO,buff,nByte);}else{close(sockfd);cout<<"client ["<<i<<"] closed connection"<<endl;client[i].fd=-1;}if(--nready==0){break;}}}}close(listenfd);close(connfd);return 0;
}

04_epoll_server.cc

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <error.h>
#include <errno.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>#include <iostream>
#include <string>#define OPEN_MAX 1024
/* #define SERV_IP "192.168.235.128" */
#define SERV_IP "127.0.0.1"
#define SERV_PORT 6888using std::cout;
using std::endl;
using std::string;/* 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/EPOLLERR */
/*     epoll_data_t data;        /1* User data variable *1/ */
/* }; */int main(int argc,char** argv)
{int cnt ;//debugint connfd,sockfd;int listenfd=socket(AF_INET,SOCK_STREAM,0);if(listenfd<0){error(1,errno,"socket");}//port ip 复用int opt=1;int retval=setsockopt(listenfd,SOL_SOCKET,SO_REUSEPORT,&opt,sizeof(opt));if(retval<0){error(1,errno,"setscockopt");}int opt2=1;retval=setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt2,sizeof(opt2));if(retval<0){error(1,errno,"setscockopt2");}//bindstruct sockaddr_in seraddr;bzero(&seraddr,sizeof(seraddr));seraddr.sin_addr.s_addr=htonl(INADDR_ANY);/* seraddr.sin_addr.s_addr=inet_pton( *//*        listenfd, SERV_IP, &seraddr.sin_addr.s_addr); */seraddr.sin_port=htons(SERV_PORT);seraddr.sin_family=AF_INET;int ret=bind(listenfd,(struct sockaddr*)&seraddr,sizeof(seraddr));if(ret<0){error(1,errno,"bind");}//监听ret=listen(listenfd,128);if(ret<0){error(1,errno,"listen");}cout<<"server is listen"<<endl;char buff[BUFSIZ],str[INET_ADDRSTRLEN];//IPV4地址的字符串表示形式的最大长度//创建红黑树的根节点(红黑树+就绪链表)int epfd=epoll_create(OPEN_MAX);/* int epfd=epoll_create1(1); */if(epfd==-1){error(1,errno,"epoll_create1");}//赋值evt,listenfd加入监听struct epoll_event evt,ep[OPEN_MAX];evt.events=EPOLLIN;evt.data.fd=listenfd;ret=epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&evt);if(ret<0){error(1,errno,"epoll_ctl(add) listenfd");}while(1){int nready=epoll_wait(epfd,ep,OPEN_MAX,-1);if(nready<0){error(1,errno,"select");}
//==============================
cout<<cnt++<<"  "<<ep[0].data.fd<<endl;
//递增的ep[0].data.fd,记录的是接收到的事件的数量
//这个上下文中是用来输出当前处理的事件的文件描述符,
//可能会是新连接的文件描述符,所以会看起来是递增的                    //02遍历nreadyfor(int i=0;i<nready;++i){//异常处理if(!(ep[i].events & EPOLLIN)){continue;}//监听到listenfd,新连接//(监听到连接事件)if(ep[i].data.fd == listenfd){struct sockaddr_in clie_addr;socklen_t clie_addr_len=sizeof(clie_addr);//新连接的套接字connfd=accept(listenfd,(struct sockaddr*)&clie_addr,&clie_addr_len);if(connfd==-1){error(1,errno,"accept");}printf("receive from %s : %d\n",inet_ntop(AF_FILE,&clie_addr.sin_addr,str,sizeof(str)),ntohs(clie_addr.sin_port));//三次握手成功//新连接加入监听evt.events=EPOLLIN;evt.data.fd=connfd;ret=epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&evt);if(ret<0){error(1,errno,"epoll_ctl(add) connfd");}}//不是连接事件--> 读写事件-->有消息else {sockfd=ep[i].data.fd;int nByte=read(sockfd,buff,sizeof(buff));//缓冲区空,即将断开if(nByte==0){ret=epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL);if(ret<0){error(1,errno,"epoll_ctl(delete)");}close(sockfd);cout<<"client ["<<sockfd<<"] closed connecttion"<<endl;}//连接异常else if(nByte<0){perror("epoll_wait error");ret=epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL);if(ret<0){error(1,errno,"epoll_ctl(delete)");}close(sockfd);}//正常通信else{for(int j=0;j<nByte;++j){buff[j]=toupper(buff[j]);//a->A}write(sockfd,buff,nByte);write(STDOUT_FILENO,buff,nByte);}}}}close(listenfd);close(connfd);return 0;
}

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

相关文章:

  • HarmonyOS 应用获取公钥和 MD5 指纹签名信息
  • 封装一个录音声音振动效果的组件
  • Java、JS与Go的扩展操作符,揭秘它们的‘魔法’!
  • ROS学习笔记13——rosbag功能包的简单使用
  • Python Flask网页开发基本框架
  • Mybatis-plus进阶篇(五)
  • 交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
  • 【QT】定时器使用
  • 虚拟机:3、(待更)WSL2安装Ubuntu系统+实现GPU直通
  • CSP-J2024年全真模拟题 阅读程序篇2
  • 几种手段mfc140u.dll丢失的解决方法,了解mfc140u.dll
  • Scrapy爬虫框架 Spider Middleware 爬虫页中间件
  • localectl 命令:系统语言、键盘布局和区域设置
  • 《微信小程序实战(3) · 推广海报制作》
  • SS-MUSIC
  • Spring Cloud Gateway组件
  • 激发AI创造力:掌握Prompt提示词的高效提问方法
  • 江科大笔记—STM32课程简介
  • 使用 nvm 管理 node 版本:如何在 macOS 和 Windows 上安装使用nvm
  • 【项目开发 | Python】基于“羊了个羊“风格的消除类小游戏
  • 云服务器使用
  • sqli-lab靶场学习(四)——Less11-14(post方法)
  • GBDT算法原理及其公式推导过程
  • 网络:UDP协议
  • linux与unix
  • 计算机网络29——Linux基本命令vim,gcc编译命令
  • uniapp离线(本地)打包
  • 如何编写一个爬虫以实时获取某平台商品价格
  • 声网SDK脚本运行错误
  • Docker + Win 10 学习记录