GO的TCP网络编程

四层网络分层 Go中主要在传输层 TCP/UDP协议上 去写Redis (net包) 系统提供Socket作为TCP网络连接的抽象,每个socket就是个连接好的(文件描述符FD作为标志) socket通信过程 如何同时操作socket?阻塞、非阻塞、IO多路复用 epoll os监控socket,

四层网络分层

Untitled.png

Go中主要在传输层 TCP/UDP协议上 去写Redis (net包)

系统提供Socket作为TCP网络连接的抽象,每个socket就是个连接好的(文件描述符FD作为标志)

socket通信过程

Untitled.png

如何同时操作socket?阻塞、非阻塞、IO多路复用 epoll

Untitled.png

os监控socket,非阻塞地去询问哪些事件发生了,os会返回事件列表,程序直接操作发生事件的socket

阻塞模型+多路复用:底层使用os的多路复用,协程层次使用阻塞模型开发,阻塞协程时进行协程休眠,等待唤醒

GO中如何抽象epoll?统一不同os的多路复用器(epoll\IOCP\Kqueue)

新建epoll_create() 注册监听事件epoll_ctl() 查询epoll_wait()

GO中使用network poller去实现不同平台的io多路复用
⇒netpollinit()\netpollopen()\netpoll() 和上面对应

netpollinit()

· 新建epoll · 新建pip管道用于中断epoll · 管道有数据到达事件注册在epoll中

netpollopen()

· 把fd传入epollctl · 还有个pd *pollDesc(记录了socket和协程的关系) · 把socket可读可写断开事件注册到epoll

netpoll()

调用epollwait(epfd, &events[128]EpollEvent)
把事件填到events。n<0 没有事件发生 retry;n>0 遍历事件数组,执行r/w表示模式(读写等)polldesc 最后返回一个协程的列表 代表有哪些socket可读写的协程列表

pollcache和pollDesc

带锁的pollDesc链表头,pollDesc是对socket的详细描述,包含rg wg读/写的等待协程

如何收发数据?

  1. G需要收发数据时,Socket已经可读写
    · g0循环调用netpoll()方法(放在gcStart里面的 循环)
    · 发现socket可读写时,判断mode(r/w) 取出wg/rg 设置为pdReady(1) 表明已经可读写
    · 协程调用pollWait()
    · 判断rg/wg是否pdReady(1)返回0
  2. Socket还不可读写
    · g0循环调用netpoll()方法(放在gcStart里面的 循环)
    · 协程调用pollWait()
    · 发现pollDesc里面的wg/rg都是0 对应rg/wg设置为协程的地址
    · gopark挂起休眠等待
    · 一旦循环发现socket可读写 查看对应rg/wg 如果为地址 直接返回协程地址
    · 调度器调度对应协程

GO如何抽象socket?

net包 go原生的网络包 实现TCP UDP HTTP等网络操作

net包里用netFD描述socket连接信息 底层记录了pollDesc等信息 还有包括他连接的地址端口等信息

net.Listen()

新建socket 执行bind;新建fd;返回TCPListener;TCPListener的FD信息加入监听(TCPListener对象本质是一个LISTEN状态的socket)

TCPListener.Accept()

直接调用socket的accept();如果失败则休眠等待新连接;新的socket包装为TCPConn变量返回;TCPConn的FD信息加入监听;TCPConn本质是一个ESTABLISHED状态的socket

TCPConn.Read()/Write()

直接调用socket的读写;失败则休眠等待可读写状态;被唤醒后调用系统socket

Untitled.png

LICENSED UNDER CC BY-NC-SA 4.0
Comment