poll小例子
#include <iostream>#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <poll.h>
#include <vector>
#include <netinet/in.h> // INADDR_ANY
#include <errno.h>
#include <arpa/inet.h> // inet_ntoa
#include <cstring>
#include <unistd.h>
int main(void)
{
// 防止服务器关闭
signal(SIGPIPE, SIG_IGN);
// 防止产生僵尸进程
signal(SIGCHLD, SIG_IGN);
// 创建socket 非阻塞 | 子进程中关闭该套接字
int listen_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
if (listen_fd == -1)
return -1;
// 初始化socket信息
struct sockaddr_in server_addr {};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(5578);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int on = 1;
int ret;
// 防止time_wait
ret = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
if (ret == -1)
return -1;
// 绑定端口
ret = bind(listen_fd, (const struct sockaddr*)&server_addr, sizeof(server_addr));
if (ret == -1)
return -1;
// 监听端口
ret = listen(listen_fd, 1);
if (ret == -1)
return -1;
// poll读事件,先加入监听客户端连接事件
struct pollfd read_pollfd;
read_pollfd.fd = listen_fd;
read_pollfd.events = POLLIN;
read_pollfd.revents= 0;
std::vector<pollfd> vec_read_poll;
vec_read_poll.push_back(read_pollfd);
// poll 服务器写事件
struct pollfd write_pollfd {};
std::vector<pollfd> vec_write_poll;
struct sockaddr_in client_addr {};
socklen_t addr_len = sizeof(struct sockaddr);
int read_ready;
int write_read_ready;
int connected_fd;
while (1)
{
read_ready = poll(vec_read_poll.data(), vec_read_poll.size(), -1);
// poll失败
if (read_ready == -1)
{
if (errno == EINTR)
continue;
if (errno == EMFILE)
{
printf("文件描述符超出上限\n");
return -1;
}
return -1;
}
// 没有客户端连接
else if (read_ready == 0)
continue;
// 客户端连接过来了
else if (vec_read_poll.revents & POLLIN)
{
--read_ready;
// 建立三次握手
connected_fd = accept4(listen_fd, (sockaddr *)&client_addr, &addr_len, SOCK_NONBLOCK | SOCK_CLOEXEC);
if (connected_fd == -1)
{
if (errno == EINTR)
continue;
else if (errno == ECONNABORTED)
{
close(connected_fd);
continue;
}
else
return -1;
}
// 注册读事件
read_pollfd.fd = connected_fd;
read_pollfd.events = POLLIN;
read_pollfd.revents = 0;
vec_read_poll.push_back(read_pollfd);
// 三次握手成功,打印客户端信息
std::cout << "client_ip = " << inet_ntoa(client_addr.sin_addr) << std::endl;
std::cout << "client_port = " << ntohs(client_addr.sin_port) << std::endl;
if (read_ready == 0)
continue;
}
// read_ready > 0 说明客户端发来信息了 遍历读事件
for (auto it = vec_read_poll.begin() + 1; it != vec_read_poll.end() && read_ready; it++)
{
// 客户端发来了消息
if (it->revents & POLLIN)
{
--read_ready;
char buf {};
ret = recv(it->fd, buf, sizeof(buf), 0);
if (ret == -1)
{
// 接收缓冲区中没有数据
if (errno == EAGAIN || errno == EWOULDBLOCK)
continue;
if (errno == EINTR)
continue;
return -1;
}
// 客户端正常调用 close 四次挥手
if (ret == 0)
{
std::cout << "client closed" << std::endl;
it = vec_read_poll.erase(it);
--it;
close(connected_fd);
continue;
}
std::cout << buf;
ret = send(it->fd, buf, strlen(buf) + 1, 0);
if (ret == -1)
{
// 如果发送缓冲区满的话,就注册写事件
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
write_read_ready = poll(vec_write_poll.data(), vec_write_poll.size(), -1);
// poll失败
if (write_read_ready == -1)
{
if (errno == EINTR)
continue;
return -1;
}
write_pollfd.fd = it->fd;
write_pollfd.events = POLLOUT;
write_pollfd.revents = 0;
vec_write_poll.push_back(write_pollfd);
continue;
}
if (errno == EINTR)
continue;
return -1;
}
// 遍历写事件
for (auto it = vec_write_poll.begin(); it != vec_write_poll.end() && write_read_ready; it++)
{
if (write_pollfd.revents & POLLOUT)
{
write_read_ready--;
send(it->fd, buf, strlen(buf) + 1, 0);
it = vec_read_poll.erase(it);
--it;
}
}
}
}
}
return 0;
}
这个能不能搞到windows上搞阿 ayaoko 发表于 2021-1-11 16:24
这个能不能搞到windows上搞阿
不能 windows 没有poll 有WSAPoll 替换就好了 pzx521521 发表于 2021-1-11 17:01
不能 windows 没有poll 有WSAPoll 替换就好了
大侠这个有没有跨平台,有没有例子给一个,多谢
页:
[1]