代码基本框架参考:https://blog.51cto.com/14569275/2538214

背景

  • 不需要不修改传入的参数数组
  • 可以监视任意个链接cat /proc/sys/fs/file-max

缺点

  • 不能确切指定有数据的socket
  • 线程不安全 结构体

函数

int poll(struct pollfd *fdarray, unsigned long nfds, int timeout)

概念 编码流程 1.定义pollfd结构体数组 2.初始化pollfd结构体数组 3.设置监听poll事件 4.等待poll事件 5.判断触发事件的描述符,并做对应处理。 触发事件 代码结构

// 定义pollfd结构体数组
struct pollfd pollfds[OPEN_MAX];
 
// 初始化pollfd结构体数组
int i;
for(i=0;i<OPEN_MAX;i++){
    pollfds[i].fd = -1;
}
int pollfds_cnt = 0;
 
// 设置监听事件
pollfds[0].fd = fd1;
pollfds[0].event = POLLRDNOM;
pollfds_cnt++;
pollfds[1].fd = fd1;
pollfds[1].event = POLLRDNORM;
pollfds_cnt++;
 
// 等待poll事件
if(poll(pollfds,pollfds_cnt,INFTIM)>0){
    int i;
    for(i=0;i<pollfds_cnt;i++){
        // 判断触发事件的描述符
        if(pollfds[i].fd == fd1 && pollfds[i].revent & POLLRDNORM){
            // do something
        }
        if(pollfds[i].fd == fd2 && pollfds[i].revent & POLLRDNORM){
            // do something
        }
    }
}

注意 struct pollfd数组的最大数是OPEN_MAX(或者linux/fs.h中的INR_OPEN_MAX ) 还可以通过如下方式查看: *cat /proc/sys/fs/file-max *ulimit 客户端代码

#include<iostream>
#include<arpa/inet.h>
#nclude<unistd.h>
#include<sys/poll.h>
#include<linux/fs.h> //OPEN_MAX
#include<strings.h>
using namespace std;

string name;

void show_connect(int fd){
//获取本地址和端口
        struct sockaddr_in  local_addr;
        socklen_t local_addr_len=sizeof(local_addr);
        bzero(&local_addr,local_addr_len);
        getsockname(fd,(struct sockaddr*)&local_addr,&local_addr_len);
            cout<<"local"<<inet_ntoa(local_addr.sin_addr)<<":"<<ntohs(local_addr.sin_port)<<endl;
        //获取远程地址和端口
            struct sockaddr_in remote_addr;
            socklen_t remote_addr_len=sizeof(remote_addr);
            bzero(&remote_addr,remote_addr_len);
            getpeername(fd,(struct sockaddr*)&remote_addr,&remote_addr_len);
            cout<<"remote"<<inet_ntoa(remote_addr.sin_addr)<<":"<<ntohs(remote_addr.sin_port)<<endl;
}

//./client ip port
int  main(int argc,char* argv[]){
        if(argc!=4){
            cout<<"usage:"<<argv[0]<<"Ip port name"<<endl;
            return 1;
        }
        name=argv[3];
        //1.创建套接字
        int connfd=socket(AF_INET,SOCK_STREAM,0);
        if(connfd==-1){
         cout<<" socket error"<<endl;
         return 1;
        }

        //2连接服务器

        struct sockaddr_in remote_addr;
        remote_addr.sin_family=AF_INET;//协议
        remote_addr.sin_addr.s_addr=inet_addr(argv[1]);//IP地址
        remote_addr.sin_port=htons(atoi(argv[2]));//端口号

        if(-1==connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){
        cout<<"connect error"<<endl;
        return 1;
        }else{
          cout<<"connect success"<<endl;
            show_connect(connfd);
        }
//定义pollfd结构体数组,最大为OPEN_MAX
//fd要监听的fd
//events要监听的事件
//revents 发生的事件
struct pollfd fds[INR_OPEN_MAX];
//数组中的fd全部设置成-1
for(int i=0;i<INR_OPEN_MAX;i++){
  fds[i].fd=-1; //-1表示不监听
 }
 int  count=0;//当前监听的fd个数
 
 //设置监听
 fds[0].fd=STDIN_FILENO;
 fds[0].events=POLLRDNORM;
 fds[1].fd=connfd;
 fds[1].events=POLLRDNRM;
 count=2;
 
 for(;;){
    if(poll(fds,count,-1)>0){
		   if(fds[0].revents & POLLRDNORM){
			  //发送数据
				string message;
				getline(cin,message);
				message=name+":"+message;
				write(connfd,message.c_str().message.size()+1);
			 } 
			 if(fds[1].revents & POLLRDNORM){
			   //接收数据
				 char buffer[1024]={0};
				 int len=read(connfd,buffer,sizeof(buffer));
				 if(len==0){
				  cout<<"server exit";
					break;
				 }else{
				   cout<<buffer<<endl;
				 }
			 }
		}
 
 }
 close(connfd);
 return 0;
 
}

服务器端

#include<iostream>
#include<arpa/inet.h>
#include<sys/poll.h>
#include<linux/fs.h> //INR_OPEN_MAX
#nclude<unistd.h>
#include<strings.h>
using namespace std;

void show_connect(int fd){
        struct sockaddr_in  local_addr;
        socklen_t local_addr_len=sizeof(local_addr);
        bzero(&local_addr,local_addr_len);
        getsockname(fd,(struct sockaddr*)&local_addr,&local_addr_len);
            cout<<"local"<<inet_ntoa(local_addr.sin_addr)<<":"<<ntohs(local_addr.sin_port)<<endl;

            struct sockaddr_in remote_addr;
            socklen_t remote_addr_len=sizeof(remote_addr);
            bzero(&remote_addr,remote_addr_len);
            getpeername(fd,(struct sockaddr*)&remote_addr,&remote_addr_len);
            cout<<"remote"<<inet_ntoa(remote_addr.sin_addr)<<":"<<ntohs(remote_addr.sin_port)<<endl;
}
void Show(struct pollfd* fds,int n){
  for(int i=0;i<n;i++){
      cout<<fds[i].fd<<" ";
	}
	cout<<endl;
}

./server ip port
int  main(int argc,char* argv[]){
        if(argc!=3){
            cout<<"usage:"<<argv[0]<<"Ip port name"<<endl;
            return 1;
        }

        //1.监听套接字
        int listenfd=socket(AF_INET,SOCK_STREAM,0);
        if(listenfd==-1){
         cout<<"listen socket error"<<endl;
         return 1;
        }
        //设置端口重复利用
         int  flag=1; setsockopt(listenfd,SQL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));

        //2.绑定

        struct sockaddr_in local_addr;
        local_addr.sin_family=AF_INET;//协议
        local_addr.sin_addr.s_addr=inet_addr(argv[1]);//IP地址
        local_addr.sin_port=htons(atoi(argv[2]));//端口号

        if(-1==bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){
        cout<<"bind error"<<endl;
        return 1;
        }else{
          cout<<"bind success"<<endl;
        }

        //3.监听设置
        if(listen(listenfd,10)==-1){
            cout<<"listen error"<<endl;
            return 1;
        }else{
           cout<<"listen success"<<endl;
        }
  struct pollfd fds[INR_OPEN_MAX];
	for(auto& fd:fds){
	  fd.fd=-1;
	}
	fds[0].fd=STDIN_FILENO;
	fds[0].events=POLLRDNORM;
	fds[1].fd=listenfd;
	fds[1].events=POLLRDNORM;
	int count=2;
	
	while(true){
	   Show(fds,count);
		 if(poll(fds,count,-1)>0){
		  if(fds[0].revents & POLLRDNORM){
			   string message;
				 getline(cin,message);
				 cin.clear();//清空输入出错
				 if(!message.empty()){
				   message="广告"+message;
					 for(int i=2;i<count;i++){
					   write(fds[i].fd,message.c_str(),message.size()+1);
					 }
				 
				 }
				 
			}
			if(fds[1].revents & POLLRDNORM){
			 struct sockaddr_in remote_addr;
			 bzero(&remote_addr,sizeof(remote_addr));
			 socklen_t remote_addr_len=sizeof(remote_addr);
			 int connfd=accept(listenfd,(struct sockaddr*)&remote_addr,&remote_addr_len);
			 if(connfd==-1){
			   cout<<"accept error"<<endl;
				 return 1;
			 }else{
			    cout<<"accept success"<<endl;
					cout<<inet_ntoa(remote_addr.sin_addr)<<":"<<ntohs(remote_addr.sin_port)<<endl;
					show_connect(connfd);
					fds[count].fd=connfd;
					fds[count].events=POLLRDNPRM;
					fds[count].revents=0;//清零
					++count;
			 }
			}
			for(int i=2;i<count;i++){
			 if(fds[i].revents & POLLRDNORM){
			      int connfd=fds[i].fd;
						char buffer[1024]={0};
						int n=read(connfd,buffer,1024);//读取客户端数据
						if(n==0){
						  cout<<"client exit"<<endl;
							close(connfd);//关闭退出的链接
							//把关闭的fd从数组中移除
							for(int j=i;j<count-1;j++){
							   fds[j]=fds[j+1];
							}
							--count;
							break;
						}else{
						  for(int j=2j<count;j++){//发送消息给所有的客户端
							if(i==j) continue;
							write(fds[j].fd,buffer,1024);
							  
							}
						
						}
			 }
			}
		 }
	}
  close(connfd);      
}