Day 9. TCP并发模型、select、poll、epoll

这篇具有很好参考价值的文章主要介绍了Day 9. TCP并发模型、select、poll、epoll。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

TCP并发模型

1.TCP多线程模型:

缺点:

1)创建线程会带来资源开销,能够实现

2.IO模型:

1)阻塞IO:没有数据到来时,可以让任务故挂起,节省CPU资源开销,提高系统效率

2)非阻塞IO:程序未接受到数据时程序一直执行,效率很低

3)异步IO:只能绑定一个文件描述符用来读取数据,但是效率很高

4)多路复用IO:

select:

        1.select监听的集合中的文件描述符有上限限制     fd_set

        2.select有内核层向用户层数据空间拷贝的过程,占用系统资源开销

        3.select必须轮询检测产生事件的文件描述符

        4.select只能工作在水平触发模式(低速模式),无法工作在边缘触发(高速模式)

poll:

        1.poll监听集合中的文件描述符没有上限

        2.poll有内核层向用户层数据空间拷贝的过程,占用系统资源开销

        3.poll必须轮询检测产生事件的文件描述符

        4.poll只能工作在水平触发模式(低速模式),无法工作在边沿触发(高速模式)

epoll:

        1.epoll没有文件描述符的上限限制

        2.epoll创建的是内核监听事件表,所以只需要在内核空间完成数据拷贝即可

        3.eopll会将产生事件的文件描述符直接返回

        4. eopll可以工作在水平触发模式(低速模式),还可以工作在边缘触发模式(高速模式)       

3.函数接口:

1)select

 int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

功能:select建听描述符集合中是否有文件描述编程ready状态

参数:nfds:最大文件买哦舒服的值+1;

           readfds:读文件描述符集合

           writefds:写文件描述符集合

           exceptfds:其余文件描述符集合

           timeout:等待的时长

                        NULL 一直等待

返回值:成功返回文件描述符集合中的文件描述个数;失败返回-1;

void FD_CLR(int fd, fd_set *set);

功能:将文件描述符fd从集合中清除 

int  FD_ISSET(int fd, fd_set *set);

功能:判断文件描述符fd是否仍在集合中 

void FD_SET(int fd, fd_set *set);

功能:将文件描述符fd加入到集合中

void FD_ZERO(fd_set *set);

功能:将文件描述符集合清0

写端

#include "head.h"
 
int main(void)
{
    int fd = 0;
    char tmpbuff[4096] = {0};
 
    mkfifo("/tmp/myfifo", 0777);
 
    fd = open("/tmp/myfifo", O_WRONLY);
    if (-1 == fd)
    {
        perror("fail to open");
        return -1;
    }
 
    while (1)
    {
        gets(tmpbuff);
        write(fd, tmpbuff, strlen(tmpbuff));
    }
    close(fd);
 
    return 0;
}

读端

#include "head.h"
 
int main(void)
{
    int fd = 0;
    int flags = 0;
    char *pret = NULL;
    ssize_t nsize = 0;
    char tmpbuff[4096] = {0};
    fd_set rdfds;
    fd_set tmpfds;
    int ret = 0;
 
    mkfifo("/tmp/myfifo", 0664);
    
    fd = open("/tmp/myfifo", O_RDONLY);
    if (-1 == fd)
    {
        perror("fail to open");
        return -1;
    }
 
    FD_ZERO(&rdfds);//将文件描述符集合清0
    FD_SET(fd, &rdfds);//将文件描述符fd加入到文件描述符集合中
    FD_SET(0, &rdfds);//将文件描述符0加入到文件描述符集合中
 
    while (1)
    {
        tmpfds = rdfds;
        ret = select(fd+1, &tmpfds, NULL, NULL, NULL);
        if (-1 == ret)
        {
            perror("fail to select");
            return -1;
        }
 
        if (FD_ISSET(fd, &tmpfds))//判断文件描述符fd是否还在文件描述符集合中
        {
            memset(tmpbuff, 0, sizeof(tmpbuff));
            read(fd, tmpbuff, sizeof(tmpbuff));
            printf("FIFO:%s\n", tmpbuff);
        }
 
        if (FD_ISSET(0, &tmpfds))
        {
            memset(tmpbuff, 0, sizeof(tmpbuff));
            gets(tmpbuff);
            printf("STDIN:%s\n", tmpbuff);
        }
 
    }
 
    close(fd);
 
    return 0;
}

2)poll

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

功能:监听文件描述符集合是否有事件发生

参数:

fds:监听文件描述符集合数组空间的首地址

nfds:监听文件描述符集合元素个数

timeout:等待的时间(-1 一直等待)

返回值:成功返回失败返回产生文件描述符的个数;失败返回-1;

struct pollfd {
               int   fd;                /* file descriptor */
               short events;      /* requested events */
               short revents;     /* returned events */
           };
        fd:监听的文件描述符

        events:要监听的事件  POLLIN:是否可读  POLLOUT:是否可写

        revents:实际产生的事件

读端

#include "head.h"
 
int main(void)
{
	int fd = 0;
	int flags = 0;
	char *pret = NULL;
	ssize_t nsize = 0;
	char tmpbuff[4096] = {0};
	struct pollfd fds[2];
	int nready = 0;
 
	mkfifo("/tmp/myfifo", 0664);
 
	fd = open("/tmp/myfifo", O_RDONLY);
	if (-1 == fd)
	{
		perror("fail to open");
		return -1;
	}
	
	fds[0].fd = fd;
	fds[0].events = POLLIN;
	fds[1].fd = 0;
	fds[1].events = POLLIN;
 
	while (1)
	{
		nready = poll(fds, 2, -1);
		if (-1 == nready)
		{
			perror("fail to poll");
			return -1;
		}
 
		if (fds[0].revents & POLLIN)
		{
			memset(tmpbuff, 0, sizeof(tmpbuff));
			read(fd, tmpbuff, sizeof(tmpbuff));
			printf("FIFO:%s\n", tmpbuff);
		}
	
		if (fds[1].revents & POLLIN)
		{
			memset(tmpbuff, 0, sizeof(tmpbuff));
			gets(tmpbuff);
			printf("STDIN:%s\n", tmpbuff);
		}
	}
 
	close(fd);
}

写端

#include "head.h"
 
int main(void)
{
	int fd = 0;
	char tmpbuff[4096] = {0};
 
	mkfifo("/tmp/myfifo", 0664);
 
	fd = open("/tmp/myfifo", O_WRONLY);
	if (-1 == fd)
	{
		perror("fail to open");
		return -1;
	}
 
	while (1)
	{
		gets(tmpbuff);
		write(fd, tmpbuff, strlen(tmpbuff));
	}
 
	close(fd);
 
	return 0;
}

3)epoll

int epoll_create(int size);

功能:创建一张内核事件表

参数:size:事件个数

返回值:成功返回文件描述符;失败返回-1;

 epoll_ctl 

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

功能:维护epoll事件表

参数:

epfd:事件表的个数

op:

        EPOLL_CTL_ADD   添加事件

        EPOLL_CTL_MOD   修改事件

        EPOLL_CTL_DEL   删除事件

fd:操作的文件描述符

event:事件对应的事件

typedef union epoll_data {
            void        *ptr;
            int          fd;
            uint32_t     u32;
            uint64_t     u64;
        } epoll_data_t;

struct epoll_event {
            uint32_t     events;      /* Epoll events */
            epoll_data_t data;        /* User data variable */
        };

返回值:成功返回0;失败返回-1;

epoll_wait 

int epoll_wait(int epfd, struct epoll_event *events,
                      int maxevents, int timeout);

功能:监听事件表的事件

参数:

epfd:文件描述符

events:存放实际产生事件的数组空间的首地址

maxevents:最多存放事件的个数

timeout:设定监听的时间(超过该时间则不再监听)

-1 一直监听直到有事件发生

返回值:

成功返回产生事件的文件描述符个数

失败返回-1 

如果时间达到仍没有事件发生返回0 

读端

#include "head.h"
 
int main(void)
{
    int fd = 0;
    int epfd = 0;
    struct epoll_event env;//epoll_ctl需要的事件的结构体
    int nready = 0;
    struct epoll_event retenv[2];
    int i = 0;
    ssize_t nsize = 0;
    char *pret = NULL;
    char tmpbuff[4096] = {0};
 
 
    mkfifo("/tmp/myfifo", 0664);
    fd = open("/tmp/myfifo", O_RDONLY);
    if (-1 == fd)
    {
        perror("fail to open");
        return -1;
    }
 
    /*创建一张2个事件的内核事件表*/
    epfd = epoll_create(2);
    if (epfd == -1)
    {
        perror("fail to create");
        return -1;
    }
 
    /*设置事件结构体的属性*/
    env.events = EPOLLIN;
    env.data.fd = fd;
    /*操作事件*/
    epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &env);
 
    env.events = EPOLLIN;
    env.data.fd = 0;
    epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &env);
 
    while (1)
    {
        /*监听事件表中的事件*/
        nready = epoll_wait(epfd, retenv, 2, -1);//第二个参数是存放实际产生事件的结构体, 最多存放的个数, 设置监听时间,-1一直监听直到有事件发生
        if (-1 == nready)
        {
            perror("fail to nready");
            return -1;
        }
 
        for (i = 0; i < nready; ++i)
        {
            if (retenv[i].data.fd == 0)//判断要操作的流是否为从终端输入
            {
                memset(tmpbuff, 0, sizeof(tmpbuff));
                gets(tmpbuff);
                printf("STDIN: %s\n", tmpbuff);
            }
 
            if (retenv[i].data.fd == fd)
            {
                memset(tmpbuff, 0, sizeof(tmpbuff));
                read(fd, tmpbuff, sizeof(tmpbuff));
                printf("FIFO: %s\n", tmpbuff);
            }
        }
    }
 
    close(fd);
 
    return 0;
}

写端文章来源地址https://www.toymoban.com/news/detail-846904.html

#include "head.h"
 
int main(void)
{
    int fd = 0;
    char tmpbuff[4096] = {0};
 
    mkfifo("/tmp/myfifo", 0664);
 
    fd = open("/tmp/myfifo", O_WRONLY);
    if (-1 == fd)
    {
        perror("fail to open");
        return -1;
    }
    
    while (1)
    {
        gets(tmpbuff);
        write(fd, tmpbuff, strlen(tmpbuff));
    }
    close(fd);
 
    return 0;
}

到了这里,关于Day 9. TCP并发模型、select、poll、epoll的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • IO多路复用中select的TCP服务器模型和poll服务模型

    服务器端 客户端 poll客户端

    2024年02月12日
    浏览(48)
  • Linux网络编程:多路I/O转接服务器(select poll epoll)

    文章目录: 一:select 1.基础API  select函数 思路分析 select优缺点 2.server.c 3.client.c 二:poll 1.基础API  poll函数  poll优缺点 read函数返回值 突破1024 文件描述符限制 2.server.c 3.client.c 三:epoll 1.基础API epoll_create创建   epoll_ctl操作  epoll_wait阻塞 epoll实现多路IO转接思路 epoll优缺点

    2024年02月11日
    浏览(52)
  • 使用select实现TCP并发服务器模型

    本期主要分享的是对于select的使用,使用select实现TCP并发服务器模型,由于之前所用到的技术知识只能够支撑我们进行单个访问,但是有了select之后呢,我们就能够实现多用户进行访问;这也是非常符合客观需求的; 这次呢我们重点来使用一下select; 用到的头文件如下: 我

    2024年02月08日
    浏览(44)
  • TCP服务器的演变过程:使用epoll构建reactor网络模型实现百万级并发(详细代码)

    手把手教你从0开始编写TCP服务器程序,体验开局一块砖,大厦全靠垒。 为了避免篇幅过长使读者感到乏味,对【TCP服务器的开发】进行分阶段实现,一步步进行优化升级。 本节,在上一章节介绍了如何使用epoll开发高效的服务器,本节将介绍使用epoll构建reactor网络模型,实

    2024年02月01日
    浏览(72)
  • linux poll,epoll,select的区别

    epoll中红黑树的作用? 红黑树(rbtree)、以及epoll的实现原理_epoll 红黑树_For Nine的博客-CSDN博客 红黑树和epoll_wait的关系? epoll_wait/就绪list和红黑树的关系 - 知乎 其他区别: 1. select 在linux内核中限制了能监听的数目上限。32位是1024,64位是2048 2. poll是将监听的对象改成了链表

    2024年02月03日
    浏览(37)
  • IO多路复用之select/poll/epoll

    掌握select编程模型,能够实现select版本的TCP服务器. 掌握poll编程模型,能够实现poll版本的TCP服务器. 掌握epoll的编程模型,能够实现epoll版本的TCP服务器. epoll的LT模式和ET模式. 理解select和epoll的优缺点对比. 提示:以下是本篇文章正文内容,下面案例可供参考 多路转接天然的是让我

    2023年04月09日
    浏览(73)
  • 网络编程详解(select poll epoll reactor)

    serverfd = socket( opt ):调用socket( )方法创建一个对应的serverfd bind( serverfd, address ):调用bind( )方法将fd和指定的地址( ip + port )进行绑定 listen( serverfd ):调用listen( )方法监听前面绑定时指定的地址 clientfd = accept( serverfd ):进入无限循环等待接受客户端连接请求 n = read( clientfd, buf

    2024年04月09日
    浏览(37)
  • select,poll,epoll阻塞IO使用示例介绍

    epoll 打开设备文件或套接字,并确保设备或套接字处于可读或可写状态。 创建一个 epoll 实例,使用 epoll_create 函数创建一个 epoll 文件描述符。 将设备文件或套接字的文件描述符添加到 epoll 实例中,使用 epoll_ctl 函数将设备文件或套接字的文件描述符添加到 epoll 实例中,并设

    2024年02月12日
    浏览(40)
  • 多路转接方案:select poll epoll 介绍和对比

    内存和外设的交互叫做IO,网络IO就是将数据在内存和网卡间拷贝。 IO本质就是等待和拷贝,一般等待耗时往往远高于拷贝耗时。所以提高IO效率就是尽可能减少等待时间的比重。 IO模型 简单对比解释 阻塞IO 阻塞等待数据到来 非阻塞IO 轮询等待数据到来 信号驱动 信号递达时

    2024年02月08日
    浏览(48)
  • 【Linux】高级IO --- 多路转接,select,poll,epoll

    所有通过捷径所获取的快乐,无论是金钱、性还是名望,最终都会给自己带来痛苦 1. 后端服务器最常用的网络IO设计模式其实就是Reactor,也称为反应堆模式,Reactor是单进程,单线程的,但他能够处理多客户端向服务器发起的网络IO请求,正因为他是单执行流,所以他的成本就

    2024年02月09日
    浏览(63)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包