在网络层,Socket 函数需要指定到底是 IPv4 还是 IPv6,分别对应设置为 AF_INET 和 AF_INET6。
另外,还要指定到底是 TCP 还是 UDP。还记得咱们前面讲过的,TCP 协议是基于数据流的,所以设置为 SOCK_STREAM,而 UDP 是基于数据报的,因而设置为 SOCK_DGRAM。
一、基于 TCP 协议的 Socket 程序函数调用过程
1、 bind 函数
TCP 的服务端要先监听一个端口,一般是先调用 bind 函数,给这个 Socket 赋予一个 IP 地址和端口。
1、为什么需要端口呢?
要知道,你写的是一个应用程序,当一个网络包来的时候,内核要通过 TCP 头里面的这个端口,来找到你这个应用程序,把包给你。
2、为什么要 IP 地址呢?
有时候,一台机器会有多个网卡,也就会有多个 IP 地址,你可以选择监听所有的网卡,也可以选择监听一个网卡,
这样,只有发给这个网卡的包,才会给你。
2、listen 函数
当服务端有了 IP 和端口号,就可以调用 listen 函数进行监听。在 TCP 的状态图里面,有一个 listen 状态,当调用这个函数之后,
服务端就进入了这个状态,这个时候客户端就可以发起连接了。
1、在内核中,为每个 Socket 维护两个队列
一个是已经建立了连接的队列,这时候连接三次握手已经完毕,处于 established 状态;
一个是还没有完全建立连接的队列,这个时候三次握手还没完成,处于 syn_rcvd 的状态。
3、accept 函数
接下来,服务端调用 accept 函数,拿出一个已经完成的连接进行处理。如果还没有完成,就要等着。
4、connect 函数
在服务端等待的时候,客户端可以通过 connect 函数发起连接。
先在参数中指明要连接的 IP 地址和端口号,然后开始发起三次握手。内核会给客户端分配一个临时的端口。
一旦握手成功,服务端的 accept 就会返回另一个 Socket。
1、这是一个经常考的知识点
就是监听的 Socket 和真正用来传数据的 Socket 是两个,一个叫作监听 Socket,一个叫作已连接 Socket。
连接建立成功之后,双方开始通过 read 和 write 函数来读写数据,就像往一个文件流里面写东西一样。
5、这个图就是基于 TCP 协议的 Socket 程序函数调用过程
6、TCP 的 Socket 是文件流
7、在内核中,Socket 是一个文件
1、task_struct
2、inode存储在内存中
3、两个队列
整个数据结构我也画了一张图。
二、基于 UDP 协议的 Socket 程序函数调用过程
1、UDP 是没有连接的
2、UDP 是没有维护连接状态的
3、这个图的内容就是基于 UDP 协议的 Socket 程序函数调用过程。
三、服务器如何接更多的项目(理论最大连接数)?
1、一个 TCP 连接。
2、对 IPv4
3、单机限制
在资源有限的情况下,要想接更多的项目,就需要降低每个项目消耗的资源数目。
四、服务器如何接更多的项目(多进程方式)?
1、代理模式
2、形象比喻
3、如何创建子公司
4、父子进程如何区别
每次接一个项目,都申请一个新公司,然后干完了,就注销掉这个公司
5、进程复制过程我画在这里。
因为复制了文件描述符列表,而文件描述符都是指向整个内核统一的打开文件列表的,因而父进程刚才因为 accept 创建的已连接 Socket 也是一个文件描述符,同样也会被子进程获得。
接下来,子进程就可以通过这个已连接 Socket 和客户端进行互通了,当通信完毕之后,就可以退出进程,那父进程如何知道子进程干完了项目,要退出呢?还记得 fork 返回的时候,
如果是整数就是父进程吗?这个整数就是子进程的 ID,父进程可以通过这个 ID 查看子进程是否完成项目,是否需要退出。
五、服务器如何接更多的项目(多线程)?
1、形象比喻
2、在 Linux 下
3、存在问题
其实 C10K 问题就是,你接项目接的太多了,如果每个项目都成立单独的项目组,就要招聘 10 万人,你肯定养不起,那怎么办呢?
六、服务器如何接更多的项目(IO 多路复用,一个线程维护多个 Socket)?
1、一个项目组支撑多个项目
2、派人盯着
项目进度墙
3、存在问题
七、服务器如何接更多的项目(IO 多路复用,从“派人盯着”到“有事通知”)?
1、有事通知
2、epoll
3、图解epoll工作流程
1、工作流程
当 epoll_ctl 添加一个 Socket 的时候,其实是加入这个红黑树,同时红黑树里面的节点指向一个结构,将这个结构挂在被监听的 Socket 的事件列表中。当一个 Socket 来了一个事件的时候,可以从这个列表中得到 epoll 对象,并调用 call back 通知它。
4、C10K 问题
八、小结
你需要记住 TCP 和 UDP 的 Socket 的编程中,客户端和服务端都需要调用哪些函数;
写一个能够支撑大量连接的高并发的服务端不容易,需要多进程、多线程,而 epoll 机制能解决 C10K 问题。