美文网首页
Socket通信

Socket通信

作者: zhouluyao | 来源:发表于2020-03-30 14:35 被阅读0次

    在网络层,Socket 函数需要指定到底是 IPv4 还是 IPv6,分别对应设置为 AF_INET 和 AF_INET6。另外,还要指定到底是 TCP 还是 UDP。还记得咱们前面讲过的,TCP 协议是基于数据流的,所以设置为 SOCK_STREAM,而 UDP 是基于数据报的,因而设置为 SOCK_DGRAM。

    TCP 协议的 Socket 程序函数调用过程

    tcp_socket.jpg

    在服务端等待的时候,客户端可以通过 connect 函数发起连接。先在参数中指明要连接的 IP 地址和端口号,然后开始发起三次握手。内核会给客户端分配一个临时的端口。一旦握手成功,服务端的 accept 就会返回另一个 Socket,就是监听的 Socket 和真正用来传数据的 Socket 是两个,一个叫作监听 Socket,一个叫作已连接 Socket。

    TCP 的 Socket 底层数据结构:

    说 TCP 的 Socket 就是一个文件流,是非常准确的。因为,Socket 在 Linux 中就是以文件的形式存在的。除此之外,还存在文件描述符。写入和读出,也是通过文件描述符。在内核中,Socket 是一个文件,那对应就有文件描述符。每一个进程都有一个数据结构 task_struct,里面指向一个文件描述符数组,来列出这个进程打开的所有文件的文件描述符。文件描述符是一个整数,是这个数组的下标。

    socket结构.jpg

    Socket结构里面有接受的队列和发送的队列,这两个队列中保存着缓存的数据.

    UDP 协议的 Socket 程序函数调用过程

    udp_socket.jpg

    UDP 是没有维护连接状态的,因而不需要每对连接建立一组 Socket,而是只要有一个 Socket,就能够和多个客户端通信。也正是因为没有连接状态,每次通信的时候,都调用 sendto 和 recvfrom,都可以传入 IP 地址和端口。

    select轮询检查文件是否可读写:

    由于 Socket 是文件描述符,因而某个线程盯的所有的 Socket,都放在一个文件描述符集合 fd_set 中,这就是项目进度墙,然后调用 select 函数来监听文件描述符集合是否有变化。一旦有变化,就会依次查看每个文件描述符。那些发生变化的文件描述符在 fd_set 对应的位都设为 1,表示 Socket 可读或者可写,从而可以进行读写操作,然后再调用 select,接着盯着下一轮的变化。。

    select 函数还是有问题的,因为每次 Socket 所在的文件描述符集合中有 Socket 发生变化的时候,都需要通过轮询的方式,也就是需要将全部项目都过一遍的方式来查看进度,这大大影响了一个项目组能够支撑的最大的项目数量。

    注册回调函数进行通知:

    如果改成事件通知的方式,情况就会好很多,项目组不需要通过轮询挨个盯着这些项目,而是当项目进度发生变化的时候,主动通知项目组,然后项目组再根据项目进展情况做相应的操作。

    能完成这件事情的函数叫 epoll,它在内核中的实现不是通过轮询的方式,而是通过注册 callback 函数的方式,当某个文件描述符发送变化的时候,就会主动通知。

    当 epoll_ctl 添加一个 Socket 的时候,其实是加入这个红黑树,同时红黑树里面的节点指向一个结构,将这个结构挂在被监听的 Socket 的事件列表中。当一个 Socket 来了一个事件的时候,可以从这个列表中得到 epoll 对象,并调用 call back 通知它。

    相关文章

      网友评论

          本文标题:Socket通信

          本文链接:https://www.haomeiwen.com/subject/gelvuhtx.html