通过poll函数编写socket。
原理:poll与select的过程差不多。不同的是select的fd集合有限制,而poll没有。poll使用pollfd结构来存储文件描述符。每个pollfd表示一个被监视的文件描述符,里面包含等待事件、文件描述符、实际发生的事件。等待事件需用户设置,表示期望系统检测文件描述符所发生的事件。实际发生事件是指系统监控后,在回调返回时设置。
server端:
#include <iostream>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <poll.h>
#include <vector>
using namespace std;
int main()
{
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1)
{
cout << "create server_fd error" << endl;
return 0;
}
struct sockaddr_in serverAttr;
serverAttr.sin_family = AF_INET;
serverAttr.sin_port = htons(5875);
serverAttr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(server_fd, (struct sockaddr*)&serverAttr, sizeof(serverAttr)) == -1)
{
perror("bind error");
return 0;
}
if (listen(server_fd, 10) == -1)
{
perror("listen error");
return 0;
}
int clientCnt = 0;
struct sockaddr_in clientAttr;
//使用数组存储pollfd,每一个pollfd结构体表示一个客户端的文件描述符
/*
struct pollfd
{
int fd; File descriptor to poll.
short int events; Types of events poller cares about.
short int revents; Types of events that actually occurred.
};
*/
struct pollfd clients[1024];
clients[0].fd = server_fd;
//设置监控读操作
clients[0].events = POLLIN;
int clNum = 0;
//初始化1024个文件描述符
for (int i = 1; i < 1024; i++)
{
clients[i].fd = -1;
}
while (1)
{
/*
int poll ( struct pollfd * fds, unsigned int nfds, int timeout);
Poll the file descriptors described by the NFDS structures starting at
FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
an event to occur; if TIMEOUT is -1, block until an event occurs.
Returns the number of file descriptors with events, zero if timed out,
or -1 for errors.
*/
if (poll(clients, clNum + 1, -1) == -1)
{
perror("poll error");
return 0;
}
//第一个是服务器的文件描述符,用来监控是有请求进来
if (clients[0].revents & POLLIN)
{
socklen_t len = sizeof(clientAttr);
int conn = accept(server_fd, (struct sockaddr*)&clientAttr, &len);
if (conn == -1)
{
perror("accept error");
continue;
}
cout << "accept client :" << inet_ntoa(clientAttr.sin_addr) << ":" << clientAttr.sin_port << endl;
//将新的请求文件描述符加到客户端数组中
int i;
for (i = 1; i < 1024; i++)
{
if (clients[i].fd == -1)
{
clients[i].fd = conn;
clients[i].events = POLLIN;
break;
}
}
clNum = clNum > i ? clNum : i;
}
//轮询客户端fd数组
char readBuf[1024] = {0};
for (int i = 1; i <= clNum; i++)
{
memset(readBuf, 0, sizeof(readBuf));
if (clients[i].revents & POLLIN)
{
//读取改客户端连接的信息
int n = read(clients[i].fd, readBuf, 1024);
cout << "read msg is " << readBuf << ",n=" << n << endl;
//回复客户端
string wrtBuf = "hello,clients[i]ient " + to_string(i);
write(clients[i].fd, wrtBuf.c_str(), wrtBuf.length() + 1);
}
}
}
return 0;
}
参考: