【一】socket是什么
从字面上的意思来理解,这玩意的中文含义叫插座,对你想的没错,就是你家用来插电器的插座,只不过你家的插座是用来导电的,而网络里面的socket是用来传导信息的。
【二】网络socket传送数据流程
我们使用tcp进行链接的时候的一般流程是这样的:
客户端:创建socket套接字,进行connect()链接,send(),或者recv()数据
服务端:创建socket套接字,进行bind绑定自己的ip和端口号,设计listen监听状态,accept()获取链接,recv或send信息。
【三】重新解析socket
尽管我们很多人见过也用过socket了,但是很多人还是对这玩意的感觉还是一个黑盒,既然你都不知道这玩意是啥了,索性我们直接忘记这玩意,重新设计一个内核网络传输功能。一般情况下,我们实现一个新的功能就需要定义一个新的结构体,那么这个结构体就叫做socket,又因为socket需要实现的功能为在多台设备之间收发数据,而设备需要标识,里面的软件也需要标识,所以socket天生就不止一个,且使用ip标识设备,port标识进程。而收发数据有很多种方式,有可靠的tcp协议有不可靠的udp协议,但是这些协议有很多相似的地方,比如收发数据时的一些逻辑,这部分的代码完全是可以复用的,按照我们面向对象编程的思想,这些不同的协议相同的部分提取出来,通过继承的方式进行复用。
而socket就是一类最基础的功能,比如接发数据的缓冲区,在socket的基础上封装成了TCP_SOCKET和UDP_SOCKET结构体,这也就是为啥我们创建socket的时候需要指定协议类型。而这类结构体是可以直接进行控制底层硬件的,例如网课,毕竟网络协议最后所有数据都 一定要从网卡里发送。
但由于这类操作的权限属实有点高,所以直接将其放到了操作系统内核里,但是在Linux系统下有一种思想叫做,一切皆文件。所以这就是为什么我们进行socket读写的时候有点像对文件进行读写了。
但是我们如何在系统的一系列的socket结构体中找到我们所需要的那个结构体呢?我们如何在操作系统中打开一个文件呢?通过文件路径打开文件,返回文件标识符fd,fd唯一标识这个文件,所以我们也可以将socket结构体抽象为这样,只不过和文件读写操作不同的是,socket结构体读写是读写到socket的结构体中的发送和接受缓冲区。
【三】对应的API接口
但是我们真不能按照文件读写的函数进行网络信号传输吧?所以我们又设计了一套网络用API结构,我们可以了解一下:send,recv,bind,listen,connect等等。
刚才我们提到传输数据的流程时,细心的小伙伴会发现,在客户端比服务端少了bind,listen和accpet流程的,这是为什么呢?
因为在服务器中,我们需要唯一确定ip地址和端口号,方便所有的用户都能找到对应的服务器,而这个相关的信息,我们可以写在相关的配置文件中,所以从用户端是一定能找到服务器的,但是从服务器的角度来说,用户端的ip是随机的,端口是随机的,我不需要去找你,也根本找不到你,也会出现端口号被占用的情况,索性不如让操作系统帮我们进行绑定,一旦进行连接,服务器这边就能记录端口号和ip地址,方便下次找到你。
缺少listen是因为客户端是连接发起端,不需要去主动监听外来连接,我们发送三次握手连接后,等待回应即可。而没有accpet就更简单了,没有人来连我,我为啥要去握手完成队列里面获取连接?更不应该去获取连接。