C++ 网络编程 自学 01

网络框架:libvent、ace、muduo


socket编程 

socket 是一套用于不同主机间通信的API,工作在TCP/IP协议栈之上,中文“套接字”

API就是应用程序编程接口

通常接口为                 IP地址                       和                     端口

                IP地址用于唯一标识网络设备                端口用于区分主机上不同应用

通过socket可以建立一条用于不同主机,不同应用之间的虚拟数据通道,点对点(应用对应用)

形象比喻就是将一条数据线连接在不同应用的插槽上。

经常用到socket的两种类型 TCP 和 UDP

TCP Transmission Control Protocol 传输控制协议

TCP协议可靠,它的底层会自动检测并传回丢失的数据包,对调用者来说,发送的数据对方一定会接收到,发送和接受顺序一致。

所以可以说TCP是基于“数据流”的协议

TCP 要求收发数据的双方扮演不同的角色:服务器和客户端。

服务器被动等待客户端连接,不能主动连接。

UDP User Datagram Protocol 用户报文协议,以报文为单位收发数据

与TCP不同,不会回传丢失的数据包,不能保证数据对方一定收到

也存在优点:低延迟,占用资源少

下面假设有很多客户端连接服务器,一提起连接就会想到TCP

因为TCP有连接,UDP没有连接

那么客户端发送到服务端,服务端会通过 receive函数接收

receive函数有四个参数

  1. fd 表示socket接口
  2. buf 表示数据存储在哪里
  3. buf长度 表示数据长度
  4. 0 固定值

但是用到receive函数的前提是知道了客户端发消息,那么怎么知道客户端发消息了呢?

这里就涉及到了 IO多路复用 

IO多路复用 有3种解决方案:select poll epoll  ,作用就是把客户端连接到服务端将IO放到一起,加入到IO多路复用,然后由组件进行管理,哪个有数据了可以立马检测出来,之后再使用receive函数进行读取。

既然提了那就说下 select poll epoll 吧。这三个都是属于系统调用。

select 有5个参数

  1. fd+1 socket接口数量,形象来说就是公司员工最大的工号
  2. 读取个数 形象来说就是午饭,选择点外卖员工的个数
  3. 写的个数 形象来说就是午饭,选择食堂员工的个数
  4. 异常个数 形象来说就是午饭,自己带饭员工的个数
  5. timeout 多长时间查一次

SYSCALL 表示系统调用   DEFINE3  表示3个参数

poll 有3个参数

  1. fds       socket 接口数量
  2. length     长度
  3. timeout    多长时间查询一次

select 和 poll 工作过程都是三步

  1. 用户空间copy到内核空间
  2. 进行遍历循环 for(;;)
  3. 内核空间copy用户空间

epoll 和 select poll 不同

epoll 有3个参数

  1. epoll_create 调用时直接在内核空间创建一个所有集合的根节点
  2. epoll_ctl 一次只增加一个接口,同样删除也是一次只删除一个
  3. epoll_wait 每次从集合堆里面把准备就绪的拿出来,从类和空间copy出来

epoll-->ntytcp 用户态的协议栈 fd

  1. epoll -->mmap 没有这一说
  2. epoll -->1024以上才有效果 也没有这一说

那今天最后一个点了,在哪些场景下select比epoll更适合呢?

epoll 底层是用的红黑树,红黑树会在后面学数据结构的时候遇到。 

红黑树有可能会为了线程安全而加锁,那么在IO数量不多、多线程或多进程同时操作的时候select会比epoll更合适。


IO 模型有哪些,讲讲理解的nio,和bio ,aio的区别是啥,谈谈reactor 模型

首先呢,先要知道:

nio     非阻塞io

bio     阻塞io

aio     异步io

reactor 反应堆

比如说有一个fd,前面讲到的socket,调用receive函数

recv(fd,buffer,length,0)

 如果说这个fd本身是阻塞的,没有设置为非阻塞,那么他默认就是阻塞的。

如果recv这个fd的时候,fd没有数据,recv这个过程就被阻塞,整个线程被挂起了。

clientfd=accept();
recv(clientfd,buffer,length,0)

这里要注意两点,

1、客户端连接accept(),对应的listen fd 默认阻塞也没设置为非阻塞,那么accept()会被挂起,阻塞,一直等待连接

2、当客户端连接,accept()返回,创建了新连接,但是recv函数里clientfd也是阻塞的,没有设置为非阻塞,那么recv也会被挂起阻塞,当客户端发送数据,recv接收数据返回,这就是阻塞io

那什么是非阻塞io呢

如果accept执行listen fd 发现是非阻塞的,一执行IO没连接,会立即返回,但是会返回非零,比如-1,然后继续执行下面操作。

如果recv里面的clientfd也是非阻塞的,没有数据的时候也是返回-1.下面接着执行,这就是非阻塞io

什么是异步io呢

非阻塞io只是限制了没读到就返回,他不知道什么时候fd就有数据了,数据没到我也不等,就往下进行。

aio呢 

fdset(fd,cb);
callback()

如果数据可读了直接callback,这就是异步io

为什么linux服务器不用异步io呢

因为Linux涉及到两个空间,一个内核空间一个用户空间

如果使用aio的callback,设想一下,多个io每个callback都要从内核空间回到用户空间,频繁调用0X80,太多就会崩溃

所以只有像磁盘读取文件读取这种io就几个或几十个的时候是可以使用aio的


那么什么是反应堆reactor

比如说有一个客户端连接了服务器,有大量的io,把每个io都放到epoll里面,然后后面就是从集合里拿出几个是触发的,遍历就绪的看哪些是可读的,哪些是可写的。

while(1)
{
    int nready=epoll_wait(epfd,events,length,-1);
    for(i=0;i

正常就是循环遍历,那么也可以通过封装升华一下

客户端连接服务器,每个io出发都会有可读、可写、出错三个事件

把io添加到epoll里面开始,就为每个io设置可读、可写、出错三个回调函数

每个io读到的数据就放到一个buffer里面

每个io写的数据放到另一个buffer里面

做出一层把数据放到发送buffer sendbuffer里,什么时候发送根本不用管,发送的时候只要设置写epollout,这个回调函数自己就可以执行,这样完全可以把epoll抽离出来。

这个时候每个io不同时间都会有不同回调函数,每个事件对应不同的反应,大量的io放到一起,就跟反应堆一样。

你可能感兴趣的:(C++开发快速记忆合集,网络编程,网络,服务器,tcp/ip,udp)