Linux C++ 网络编程学习系列(3)——多路IO之poll实现
poll实现多路IO
- 源码地址:https://github.com/whuwzp/linuxc/tree/master/poll
- 源码说明:
- server.cpp: 监听127.1:6666,功能是将收到的小写转大写
- include/wrap.cpp: 封装的一些socket基本操作,加了基本的错误处理
1. 概要
一定先select实现,poll是select的改进版:,有以下不同
- 输入输出参数方面
- select: 需要allfds和readfds两个集合,因为readfds作为输入输出参数,每次select前都要用allfds赋值给它
- poll: pollfd结构体中,有events和revents两个,分别用来表示输入输出
- 监听集合的形式
- select: 用fd_set位图标记需要监听的fd
- poll: 用pollfd结构体中的fd成员标记,用结构体数组表示需要监听的集合
- 监听信号类型
- select: 用readfds, writefds集合分别表示
- poll: 用POLLIN,POLLOUT表示,
fds[0].events = POLLIN
- 判断是否有信号
- select: 用
FD_ISSET(fd,readfds) - poll: 用
fds[0].revents & POLLIN
- select: 用
2. 核心代码
#include "include/wrap.h"
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <netinet/in.h>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdnoreturn.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h> /* See NOTES */
#include <unistd.h>
#include <wait.h>
#define LOCALIP "127.0.0.1"
#define PORT 6666
void handler(char *in, char *out) {
for (int i = 0; i < (int)strlen(out) + 1; ++i) {
out[i] = toupper(in[i]);
}
}
int workthread(const int &fd_client) {
char recvbuf[2048] = {0};
char sendbuf[2048] = {0};
int ret = 0;
ret = (int)Read(fd_client, recvbuf, 2048);
if (ret <= 0) {
printf("ret==0\n");
return ret;
}
handler(recvbuf, sendbuf);
ret = (int)Write(fd_client, sendbuf, strlen(sendbuf) + 1);
return ret;
}
void startsock(int &fd, struct sockaddr_in &addr, const char *ip,
const int port) {
fd = Socket(AF_INET, SOCK_STREAM, 0);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip);
addr.sin_port = htons(port);
}
int main() {
int fd_server = 0;
int fd_client = 0;
int ret = 0;
struct sockaddr_in sock_client;
struct sockaddr_in sock_server;
socklen_t client_len = (socklen_t)sizeof(sock_client);
int opt = 0;
struct pollfd fds[FD_SETSIZE];
int maxi = 0;
int nselect = 0;
int i = 0;
startsock(fd_server, sock_server, LOCALIP, PORT);
opt = 1;
Setsockopt(fd_server, SOL_SOCKET, SO_REUSEADDR, &opt,
(socklen_t)sizeof(opt));
Bind(fd_server, (struct sockaddr *)&sock_server, sizeof(sock_server));
Listen(fd_server, 5);
for (i = 0; i < FD_SETSIZE; ++i) {
fds[i].fd = -1;
fds[i].events = POLLIN;
}
fds[0].fd = fd_server;
maxi = 0;
while (true) {
printf("polling...\n");
nselect = poll(fds, (unsigned long)maxi+1, -1);
if (nselect == -1) {
if (errno == EINTR) {
continue;
} else {
perror_exit("poll failed");
}
}
printf("get %d select\n", nselect);
if (fds[0].revents & POLLIN) {
fd_client =
Accept(fd_server, (struct sockaddr *)&sock_client, &client_len);
printf("accept: %s: %d\n", inet_ntoa(sock_client.sin_addr),
ntohs(sock_client.sin_port));
for (i = 0; i < FD_SETSIZE; ++i) {
if (fds[i].fd != -1) continue;
fds[i].fd = fd_client;
break;
}
printf("i: %d, FD_SETSIZE: %d\n", i, FD_SETSIZE);
if (i == FD_SETSIZE) perror_exit("too many clients");
if (i > maxi) maxi = i;
nselect--;
}
printf("going to find client, maxi: %d, nselect: %d\n", maxi, nselect);
for (i = 0; (i <= maxi) && (nselect > 0); ++i) {
if (!( fds[i].revents & POLLIN )) continue;
printf("find client %d\n", i + 1);
ret = workthread(fds[i].fd);
if (ret <= 0) {
Close(fds[i].fd);
fds[i].fd = -1;
}
nselect--;
}
sleep(3);
}
Close(fd_server);
for (i = 0; i < FD_SETSIZE; ++i) {
if (fds[i].fd == -1) continue;
Close(fds[i].fd);
}
}
3. 参考网址
Linux C++ 网络编程学习系列(3)——多路IO之poll实现的更多相关文章
- Linux C++ 网络编程学习系列(1)——端口复用实现
Linux C++ 网络编程学习系列(1)--端口复用实现 源码地址:https://github.com/whuwzp/linuxc/tree/master/portreuse 源码说明: serv ...
- Linux C++ 网络编程学习系列(6)——多路IO之epoll高级用法
poll实现多路IO 源码地址:https://github.com/whuwzp/linuxc/tree/master/epoll_libevent 源码说明: server.cpp: 监听127. ...
- Linux C++ 网络编程学习系列(5)——多路IO之epoll边沿触发
多路IO之epoll边沿触发+非阻塞 源码地址:https://github.com/whuwzp/linuxc/tree/master/epoll_ET_LT_NOBLOCK_example 源码说 ...
- Linux C++ 网络编程学习系列(4)——多路IO之epoll基础
epoll实现多路IO 源码地址:https://github.com/whuwzp/linuxc/tree/master/epoll 源码说明: server.cpp: 监听127.1:6666,功 ...
- Linux C++ 网络编程学习系列(2)——多路IO之select实现
select实现多路IO 源码地址:https://github.com/whuwzp/linuxc/tree/master/select 源码说明: server.cpp: 监听127.1:6666 ...
- Linux C++ 网络编程学习系列(7)——mbedtls编译使用
mbedtls编译使用 环境: Ubuntu18.04 编译器:gcc或clang 编译选项: 静态编译使用 1. mbedtls源码 下载地址: https://github.com/ARMmbed ...
- Linux C网络编程学习笔记
Linux C网络编程总结报告 一.Linux C 网络编程知识介绍: 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户端:(client) 在网络程序中, ...
- linux下网络编程学习——入门实例ZZ
http://www.cppblog.com/cuijixin/archive/2008/03/14/44480.html 是不是还对用c怎么实现网络编程感到神秘莫测阿,我们这里就要撕开它神秘的面纱, ...
- Linux下网络编程学习杂记
1.TCP/IP协议的体系结构包含四层:应用层(负责应用程序的网络服务,通过端口号识别各个不同的进程)->传输层(传输控制层协议TCP.用户数据报协议UDP.互联网控制消息协议ICMP)-> ...
随机推荐
- 蓝桥杯vip题阶乘计算
蓝桥杯vip题阶乘计算 详细题目 输入一个正整数n,输出n!的值. 其中n!=123*-*n. 算法描述 n!可能很大,而计算机能表示的整数范围有限,需要使用高精度计算的方法.使用一个数组A来表示一个 ...
- DOTNET CORE源码分析之IOC容器结果获取内容补充
补充一下ServiceProvider的内容 可能上一篇文章DOTNET CORE源码分析之IServiceProvider.ServiceProvider.IServiceProviderEngin ...
- VMware虚拟机安装Mac OS X 10.12
VMware Workstation Pro 14 安装Mac OS X 10.12 下面是所需要的补丁工具及镜像 VMware Workstation unlocker-master(OS X 虚拟 ...
- HTML,CSS,JavaScript,json,xml之间的关系
1.浏览器工作原理: https://blog.csdn.net/Luncles/article/details/80320082 2.HTML,XML,JSON之间的关系: https://blog ...
- Hibernate一对多
例如:一个用户可以对应多个订单 但一个订单只能对应一个用户 1.创建实体类 2.编写映射文件 <?xml version="1.0"?> <!DOCTYPE h ...
- python报错:ERROR: No matching distribution found for dns.resolver
可能有的小伙伴在安装dns.resolver的时候会遇到这个问题: 我百度的时候别人是: pip install dns-python 但是我这样安装也还是错误.有些时候是这个包改名了所以你没有搜索到 ...
- 基于Modbus三种CRC16校验方法的性能对比
目录 1.背景介绍 2. CRC校验的三种方法 2.1. 直接计算CRC校验 2.2. 查短表法计算CRC16校验 2.3.查大表法计算CRC16校验 3.三种校验方式的测试方法 3.1.直接计算CR ...
- mysql数据库中的mybatis中xml解决in不起作用的问题
在sql语句中,某个字段进行in条件的时候,不起作用, 但是执行语句查询为null数据,但是根据表中数据来看是不可能有null数据的可能性的,所以不知道什么原因导致数据出不来 我因此想到以下解决办法来 ...
- HDU - 1503 最长公共子序列记录路径
题意:先给两个水果的名字然后得出一个最短的序列包含这两个词. 思路:我一开始的思路是先求出最长公共子序列,然后做一些处理将其他的部分输出来:两种水果的字符串和最长公共子序列的字符串这三个字符串做对比, ...
- python中的函数及作用域的理解
内置函数 常用的几个内置函数 function des len 求长度 min 求最小值 max 求最大值 sorted 排序 reversed 反向 sum 求和 进制转换函数 function d ...