【网络】代理服务器收尾及高级IO

全是通俗易懂的讲解,如果你本节之前的知识都掌握清楚,那就速速来看我的笔记吧~  

自己写自己的八股!让未来的自己看懂! (全文手敲,受益良多)  

 本文主要带你了解什么是高级IO,以及常见的多路复用 接口。具体代码使用在下一篇文章


续上文收尾: 

        我们要访问目标服务器,一定会经过运营商。报文内容都会经过运营商,所以运营商可以对这些报文做分析,对非法的请求(访问外网)做拦截。有那么一种服务器,在特殊地区,但是可以访问外网,我们可以通过访问这个服务器,进而访问外网,规避运营商的检测。

        常规情况下,http默认携带的是非http的其他数据。HTTP 隧道技术是一种通过 HTTP 协议来传输非 HTTP 数据的方法,它允许在 HTTP 连接上封装其他协议(如 TCP、UDP 等)的数据,从而突破网络限制或绕过防火墙的某些规则,实现特定应用的通信。

NAT和代理服务器

路由器往往都具备 NAT 设备的功能, 通过 NAT 设备进行中转, 完成子网设备和其他子

网设备的通信过程.

  代理服务器看起来和 NAT 设备有一点像. 客户端向代理服务器发送请求, 代理服务器将

请求转发给真正要请求的服务器; 服务器返回结果后, 代理服务器又把结果回传给客户端.

那么 NAT 和代理服务器的区别有哪些呢?

  • 从应用上讲, NAT 设备是网络基础设备之一, 解决的是 IP 不足的问题. 代理服务器则是更贴近具体应用, 比如通过代理服务器进行翻墙, 另外像迅游这样的加速器,也是使用代理服务器.
  • 从底层实现上讲, NAT 是工作在网络层, 直接对 IP 地址进行替换. 代理服务器往往工作在应用层.
  • 从使用范围上讲, NAT 一般在局域网的出口部署, 代理服务器可以在局域网做,也可以在广域网做, 也可以跨网.
  • 从部署位置上看, NAT 一般集成在防火墙, 路由器等硬件设备上, 代理服务器则是一个软件程序, 需要部署在服务器上.

代理服务器是一种应用比较广的技术.

• 翻墙: 广域网中的代理.

• 负载均衡: 局域网中的代理.

高级IO

IO:输入Input输出Output。我们以读写为例:如果我们read,但是接受缓冲区没有数据,就会阻塞地等,write也一样。

  1. 应用层read&&write的时候,本质就是把数据从应用层给OS——本质就是拷贝函数
  2. IO=等待+拷贝。在等read时接受缓冲区有没有数据,write时发送缓冲区有没有空余位置。所以要进行拷贝,必须判断条件(读写事件)成立。
    什么叫做高效IO呢?
    单位时间内,IO过程中,等的比重越小,IO效率越高。几乎所有提高IO效率的策略,本质上就是让等的比重越小。

五种IO模型

  1. 阻塞式IO(read,write就是这种)
  2. 非阻塞式IO,非阻塞轮询
  3. 信号驱动式IO
  4. 多路复用,多路转接
  5. 异步IO

前4种IO称为同步IO

 阻塞式IO和非阻塞IO有什么区别?

  答:IO=等待+拷贝。等的方式不同而已,非阻塞IO可以在等的时候(非阻塞轮询)做其他事情。IO上效率没区别。

同步IO和异步IO有什么区别?

  答:二者本质是有没有参与IO,只要参与等或拷贝,就参与了IO。同步参与了IO,异步只是发起IO,没有参与IO,拿起结果就行。

同步IO和线程同步有关系吗?

  答:没有关系。同步IO是IO上的,线程同步是2个线程谁先谁后。

阻塞IO:

非阻塞IO:

信号驱动IO:

多路转接IO:

异步IO:

非阻塞IO

fcntl

一个文件描述符, 默认都是阻塞 IO.

函数原型如下.

#include <unistd.h>

#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );

传入的 cmd 的值不同, 后面追加的参数也不相同.

fcntl 函数有 5 种功能:

• 复制一个现有的描述符(cmd=F_DUPFD).

• 获得/设置文件描述符标记(cmd=F_GETFD 或 F_SETFD).

• 获得/设置文件状态标记(cmd=F_GETFL 或 F_SETFL).

• 获得/设置异步 I/O 所有权(cmd=F_GETOWN或 F_SETOWN).

• 获得/设置记录锁(cmd=F_GETLK,F_SETLK 或 F_SETLKW).

我们此处只是用第三种功能, 获取/设置文件状态标记, 就可以将一个文件描述符设置为非阻塞.

实现函数 SetNoBlock

基于 fcntl, 我们实现一个 SetNoBlock 函数, 将文件描述符设置为非阻塞.

void SetNoBlock(int fd) 
{

    int fl = fcntl(fd, F_GETFL);

    if (fl < 0) 
    {

        perror("fcntl");

        return;
    
    }
    
    fcntl(fd, F_SETFL, fl | O_NONBLOCK);

}

• 使用 F_GETFL 将当前的文件描述符的属性取出来(这是一个位图).

• 然后再使用 F_SETFL 将文件描述符设置回去. 设置回去的同时, 加上一个O_NONBLOCK 参数.

阻塞式正常读:                                               非阻塞:

一旦我们设置为非阻塞,如果底层fd数据没有就绪,recv/read/write/send,返回值会以出错的形式返回。A.真的出错了,B.底层没有就绪。通过errno区分!!!

多路转接——select

select只负责等,一次等待多个fd。

返回值:大于0:有n个fd就绪了,等于0:超时,没有错误,但是没有fd就绪,小于0:等待出错了。

nfds:n个fd里面最大的fd+1。

timeout是输入输出型参数:

fd_set:内核提供的数据类型,它是位图。

Fd_set *readfds 是输入输出型参数,

   输入时:用户告诉内核,我给你一个或者多个fd,你要帮我关心fd上面的读事件,如果就绪了,要告诉我。

输出时:内核告诉用户,你让我关心的多个fd中,有哪些已经就位了,你快去读吧。

比特位的位置,表示文件描述符的编号,比特位的内容表示是否需要内核关心,上面的读事件已经就绪了。

结论:fd_set是一张位图,让用户,内核之间传递fd是否就绪的信息的.注定了,使用select的时候,一定有大量的位图操作。

代码:

数据获取上来了,不可以直接读取。目前代码是单进程,建立连接的时候,不一定发消息了,所以read可能会阻塞住,必须要让select处理,将新连接交给select。

Select缺点

  1. 等待的fd是有上线的,因为位图有上线
  2. 输入输出型参数比较多,数据拷贝的频率比较高
  3. 输入输出型参数比较多,每次都要对关心的fd进行事件重置
  4. 使用第三方数组管理用户的fd,用户层需要多次遍历。内核中检测fd事件就绪,也要遍历

为了解决这些缺点,我们有另一个多路转接的方案

Poll

poll:只负责等待,

将输入输出事件进行了分离!!

Poll也有在用户层,内核方面的遍历效率问题。为了解决我们有epoll


本文主要是概念,篇幅不多,下篇文章才是重头戏!

         下一章我将详细介绍,select,poll,epoll的使用~期待你的关注👉 【A charmer】

评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值