【从零开始的嵌入式生活】网络编程5——IO多路复用

简介: 【从零开始的嵌入式生活】网络编程5——IO多路复用

今天继续网络编程,基本的TCP和UDP实现方式我们已经可以实现了,接下来就是学习一些更加底层的原理了,预计这部分是需要七天文章对应一星期的写作。这周刚好完结,希望有人愿意跟我一起学习呀。


🧑🏻作者简介:一个学嵌入式的年轻人

✨联系方式:2201891280(QQ)

📔源码地址:https://gitee.com/xingleigao/study_qianrushi

⏳全文大约阅读时间: 60min


文章目录

IO模型及多路复用

IO模型

阻塞I/O模式

读阻塞

写阻塞

非阻塞模式I/O(不常用)

多路复用IO

1.fd_set()

2.select

写在最后

IO模型及多路复用

IO模型

在UNIX/Linux下主要有四种I/O模型


阻塞I/O:

最常用

非阻塞I/O:

可防止进程阻塞在I/O操作上,需要轮询

I/O多路复用

允许同时对多个I/O进行控制

信号驱动I/O:

一种异步通信模式

阻塞I/O模式

阻塞I/O模式时最普遍使用的I/O模式,大部分程序使用的都是阻塞模式的I/O

缺省情况下,套接字建立后所处于的模式就是阻塞式I/O模式

之前使用的很多函数在调用的时候会发生阻塞


读操作中 read、recv、recvfrom

写操作中的 write、send、sendto默认不阻塞

其他操作:accept、connect

读阻塞

进程调用read函数从套接字上读取数据,当套接字的接收缓冲区还没有数据可读,就会阻塞。

它会一直阻塞,等待套接字的接收缓冲区有数据可读。

经过一段时间后,缓冲区内接收数据,于是内核便去唤醒该进程,然后访问。

如果进程阻塞过程中,对方发生故障,就会永远阻塞下去。

写阻塞

写操作发生阻塞的情况要比读操作少很多,主要时发生在要写入的缓冲区的大小小于要写入的数据量。

这些,写操作不进行任何拷贝工作,讲发生阻塞。

一旦发送缓冲有足够的空间,内核将唤醒进程,将数据从用户缓冲区拷贝到相应的发送数据缓冲区。

UDP不等待确认,没有实际的发送缓冲区,所以UDP不存在发送缓冲区满的情况,在UDP套接字上执行写操作永远不会阻塞。

非阻塞模式I/O(不常用)

当我们将一个套接字设置为非阻塞模式,我们相当于告诉系统内核:“当请求I/O操作不能完成的时候不要休眠我,而是返回一个错误给我”。

当一个应用使用了非阻塞模式的套接字,它需要使用一个循环来不停测试是否一个文件描述符有数据可读(polling)

应用程序不停的polling内核来检查是否I/O操作已经就绪,这是一个极浪费CPU资源的操作。

非阻塞模式的实现


1、fcntl()函数

int fcntl(int fd, int cmd, long arg);
int flag;
flag = fcntl(sockfd, F_GETFL, 0);
flag |= O_NONBLOCK;
fcntl(sockdf, F_SETEL, flag);

int b_on = 1;

ioctl(sock_fd, FIONBIO, &b_on);

2、ioctl()函数

 
         


多路复用IO

基本常识:

Linux中每个进程默认情况下,最多可以打开1024个文件,最多有1024哥文件描述符

文件描述符特点:

1. 非负整数

2. 从最小的数字分配

3. 每个进程启动时默认打开0、1、2三个文件描述符

多路复用针对不止套接字,也针对普通文件描述符。


1.fd_set()

void FD_ZERO(df_set *fdset)   //清空集合
void FD_SET(int fd, fd_set *fdset)  //把fd加入集合
void FD_CLR(int fd, fd_set *fdset)  //从集合中删去fd
int FD_ISSET(int fd, set *fdset)  //判断fd是否在set中


2.select

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


一般:填读集合,写集合填NULL,异常集合(带外数据)一般填NULL



struct timeval{
  long tv_sec;  /*seconds*/
  long tv_usec; /*microsecods*/
};


时间单位:1秒(s) = 103毫秒(ms) = 106微秒(us)=109纳秒(ns) = 1012皮秒(ps)

注:select推出后,集合表示有数据的集合,内核对fd_set进行了改变。


if(FD_ISSET(fd, &Rset){
  1. 若是监听套接字有数据,则有新客户端链接,则accept()
  2 .若是建立的连接套接字有数据,则读数据
  }


示例代码:


#include "net.h"
#define QUIT_STR "quit"
int main(void){
        int fd = -1;
        struct sockaddr_in sin;
        /*创建sockt fd*/
        if((fd = socket(AF_INET, SOCK_STREAM, 0) ) < 0){
               perror("socket");
                exit(1);
        }
        /*2.连接服务器*/
        bzero(&sin, sizeof(sin));
        sin.sin_family = AF_INET;
        sin.sin_port = htons(SERV_PORT); //网络字节序的端口号转换
        //sin.sin_addr = inet_addr(SERV_IP_ADDR); //IPV4
        if(inet_pton(AF_INET, SERV_IP_ADDR,(void *)&sin.sin_addr) != 1){
                perror("inet_pton");
                exit(1);
        }
        if(connect(fd, (struct sockaddr *)&sin, sizeof(sin)) <0){
                perror("connect");
                exit(1);
        }
        fd_set rset;
        int maxfd = -1;
        struct timeval tout;
        char buf[BUFSIZ];
        int ret;
        while(1){
                FD_ZERO(&rset);
                FD_SET(0, &rset);
                FD_SET(fd, &rset);
                maxfd = fd;
                tout.tv_sec = 5;
                tout.tv_usec = 0;
                select(maxfd + 1, &rset, NULL, NULL, &tout);
                if(FD_ISSET(0,&rset)){
                        bzero(buf, BUFSIZ);
                        do{
                                ret = read(0, buf, BUFSIZ - 1);
                        }while(ret <0 &&EINTR == errno);
                        if(ret < 0){
                                continue;
                        }
                        if(!ret) break; //服务器关闭
                        if(write(fd, buf, strlen(buf)) < 0){
                                perror("write() to socket");
                                continue;
                        }
                        if(!strncasecmp(buf, QUIT_STR, strlen(QUIT_STR))){
                                printf("Client is exiting!\n");
                                break;
                        }
                }
                if(FD_ISSET(fd, &rset)){//服务器给发送过了数据
                        //的读取套接字数据,处理
                        bzero(buf, BUFSIZ);
                        do{
                                ret = read(fd, buf, BUFSIZ - 1);
                        }while(ret <0 &&EINTR == errno);
                        if(ret < 0){
                                perror("read from socket");
                                continue;
                        }
                        if(!ret) break; //服务器关闭
                        printf("serve send mesg:%s\n",buf);
                        if((strlen(buf) > strlen(SERV_RESP_STR)) && !strncasecmp(buf + strlen(SERV_RESP_STR), QUIT_STR, strlen(QUIT_STR))){
                                printf("Client is exiting!\n");
                                break;
                        }
                }
        }
        /*4.关闭服务器*/
        close(fd);
        return 0;
}


写在最后

放假这两天有些懒了,今天我要更完这部分内容,主要是后面的用的也不多,前面的应用较多大家跟我一起改变世界。啊哈哈哈,求求大家给个三连再走吧


相关文章
|
1月前
|
存储 Linux C语言
Linux C/C++之IO多路复用(aio)
这篇文章介绍了Linux中IO多路复用技术epoll和异步IO技术aio的区别、执行过程、编程模型以及具体的编程实现方式。
85 1
Linux C/C++之IO多路复用(aio)
|
1月前
|
网络协议 前端开发 Java
网络协议与IO模型
网络协议与IO模型
网络协议与IO模型
|
21天前
|
网络协议 物联网 API
Python网络编程:Twisted框架的异步IO处理与实战
【10月更文挑战第26天】Python 是一门功能强大且易于学习的编程语言,Twisted 框架以其事件驱动和异步IO处理能力,在网络编程领域独树一帜。本文深入探讨 Twisted 的异步IO机制,并通过实战示例展示其强大功能。示例包括创建简单HTTP服务器,展示如何高效处理大量并发连接。
39 1
|
22天前
|
存储 关系型数据库 MySQL
查询服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息
查询服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息
195 2
|
1月前
|
开发者
什么是面向网络的IO模型?
【10月更文挑战第6天】什么是面向网络的IO模型?
21 3
|
1月前
|
数据挖掘 开发者
网络IO模型
【10月更文挑战第6天】网络IO模型
41 3
|
1月前
|
缓存 Java Linux
硬核图解网络IO模型!
硬核图解网络IO模型!
|
1月前
|
数据挖掘 开发者
网络IO模型如何选择?
网络IO模型如何选择?【10月更文挑战第5天】
19 2
|
20天前
|
网络协议 调度 开发者
Python网络编程:Twisted框架的异步IO处理与实战
【10月更文挑战第27天】本文介绍了Python网络编程中的Twisted框架,重点讲解了其异步IO处理机制。通过反应器模式,Twisted能够在单线程中高效处理多个网络连接。文章提供了两个实战示例:一个简单的Echo服务器和一个HTTP服务器,展示了Twisted的强大功能和灵活性。
30 0
|
1月前
|
Linux C++
Linux C/C++之IO多路复用(poll,epoll)
这篇文章详细介绍了Linux下C/C++编程中IO多路复用的两种机制:poll和epoll,包括它们的比较、编程模型、函数原型以及如何使用这些机制实现服务器端和客户端之间的多个连接。
24 0
Linux C/C++之IO多路复用(poll,epoll)
下一篇
无影云桌面