代码基本框架参考: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);
}