socket原理
socket为啥要有端口:确定一个链路的是一个四元组
Socket编程
socket通信
你做过socket编程吗,socket是怎么实现知道有连接过来的
说说WebSocket与socket的区别
首先Socket == 不属于协议范畴 ,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用来实现进程在网络中的通信。
WebSocket是应用层协议,是一种让客户端和服务器之间能进行双向实时通信==的技术。
WebSocket 更易用,而 Socket 更灵活。主机 A 的应用程序要能和主机 B 的应用程序通信,必须通过 Socket 建立连接,而建立 Socket 连接必须需要底层 TCP/IP 协议来建立 TCP 连接。建立 TCP 连接需要底层 IP 协议来寻址网络中的主机。网络层使用的 IP 协议可以帮助我们根据 IP 地址来找到目标主机,但是一台主机上可能运行着多个应用程序,如何才能与指定的应用程序通信就要通过 TCP 或 UDP 的地址也就是端口号来指定。这样就可以通过一个 Socket 实例唯一代表一个主机上的一个应用程序的通信链路了。而 WebSocket 则不同,它是一个完整的 应用层协议,包含一套标准的 API 。
Socket 是传输控制层的接口,用户可以通过 Socket 来操作底层 TCP/IP 协议族通信。Socket是对TCP/IP的封装,WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次 HTTP 握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
同一时间里,双方都可以主动向对方发送数据。这就是所谓的全双工。而现在使用最广泛的HTTP/1.1,也是基于TCP协议的,同一时间里,客户端和服务器只能有一方主动发数据,这就是所谓的半双工。因为HTTP协议设计之初考虑的是看看网页文本的场景,能做到客户端发起请求再由服务器响应,未考虑网页游戏这种,客户端和服务器之间都要互相主动发大量数据的场景,为了更好支持这个场景我们需要另一个TCP的新协议,因此新的应用层协议被设计出来,虽然带有socket,但是与socket毫无关系。
浏览器在TCP三次握手建立连接后,都统一使用HTTP协议先进行一次通信。
Connection: Upgrade
Upgrade: WebSocket
Sec-WebSocket-Key: T2a6wZlAwhgQNqruZ2YUyg==\r\n
如果服务器正好支持升级成WebSocket协议就会走WebSocket握手流程,同时根据客户端生成的base64码,用某个公开算法变成另一段字符串,放在Sec-WebSocket-Accept
里,同时带上101状态码(协议切换)发回给浏览器。
HTTP/1.1 101 Switching Protocols\r\n
Sec-WebSocket-Accept: iBJKv/ALIW2DobfoA4dmr3JHBCY=\r\n
Upgrade: WebSocket\r\n
Connection: Upgrade\r\n
WebSocket只有在建立连接(利用HTTP协议加上一些特殊的 header 头进行握手升级操作,升级成功后就跟 HTTP 没有任何关系了)时才用到了HTTP,升级完成之后就跟HTTP没有任何关系了。
WebSocket完美继承了 TCP 协议的全双工能力,并且还贴心的提供了解决粘包的方案。
它适用于需要服务器和客户端(浏览器)频繁交互的大部分场景,比如网页/小程序游戏,网页聊天室,以及一些类似飞书这样的网页协同办公软件。
在使用 WebSocket 协议的网页游戏里,怪物移动以及攻击玩家的行为是服务器逻辑产生的,对玩家产生的伤害等数据,都需要由服务器主动发送给客户端,客户端获得数据后展示对应的效果。
socket通常称为“套接字”,用于描述IP地址和端口,是一个通信链的句柄。应用程序通过套接字向网络发出请求或应答网络请求。服务器和客户端通过socket进行交互。服务器需要绑定在本机的某个端口号上,客户端需要声明自己连接哪个地址的哪个端口,这样服务器和客户端就能连接了。
socket一般用于比较即时的通信和实时性较高的情况,比如推送,聊天,保持心跳长连接等,对比http一般用于实时性要求不那么高的情况,比如信息反馈,图片上传,获取新闻信息等。
监听的socket和真正用来传送数据的socket,属于两个socket,一个叫做监听socket,一个叫做已完成连接socket。
需要注意服务端调用accept时,连接成功了就会返回一个已完成连接的socket,后续用来传输数据。
成功连接建立之后,双方开始通过 read 和 write 函数来读写数据,就像往一个文件流里面写东西一样。
Linux内核维护两个队列:
半连接队列(SYN 队列):接收到一个 SYN 建立连接请求,处于 SYN_RCVD 状态;
全连接队列(Accpet 队列):已完成 TCP 三次握手过程,处于 ESTABLISHED 状态;
(1)服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。
(2)客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
(3)连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
客户端协议栈向服务端发送了SYN包,告诉服务端当前发送序号client_isn,客户端进入SYN_SENT状态
服务端协议栈收到这个包之后,和客户端进行ACK应答,应答client_isn+1,表示对SYN包client_isn的确认,同时服务端也发送一个SYN包,告诉客户端当前我的发送序列号为server_isn,服务端进入 SYN_RCVD 状态;客户端协议栈收到ACK之后使得应用程序connect调用返回,表示客户端到服务端的单向连接建立成功,客户端状态为ESTABLISHED。同时客户端协议栈对服务端的SYN包进行应答,应答数据为server_isn+1;ACK应答包到达服务端,服务端TCP连接进入ESTABLISHED状态,同时服务端协议栈使得accept阻塞调用返回,这个时候服务端到客户端单向连接建立成功。至此,客户端和服务端两个方向的连接都建立成功。
客户端connect成功返回是在第二次握手,服务端accept成功返回是在第三次握手成功之后
客户端调用 close,表明客户端没有数据需要发送了,则此时会向服务端发送 FIN 报文,进入 FIN_WAIT_1 状态;服务端接收到了 FIN 报文,TCP 协议栈会为 FIN 包插入一个文件结束符 EOF 到接收缓冲区中,应用程序可以通过 read 调用来感知这个 FIN 包。这个 EOF 会被放在已排队等候的其他已接收的数据之后,这就意味着服务端需要处理这种异常情况,因为 EOF 表示在该连接上再无额外数据到达。此时,服务端进入 CLOSE_WAIT 状态;接着,当处理完数据后,自然就会读到 EOF,于是也调用 close 关闭它的套接字,这会使得服务端发出一个 FIN 包,之后处于 LAST_ACK 状态;客户端接收到服务端的 FIN 包,并发送 ACK 确认包给服务端,此时客户端将进入 TIME_WAIT 状态;服务端收到 ACK 确认包后,就进入了最后的 CLOSE 状态;客户端经过 2MSL 时间之后,也进入 CLOSE 状态;
可以,accept不参与TCP三次握手,它只是负责从TCP全连接队列中取出一个已经建立连接的socket,用户层通过accept系统调用拿到了已经建立连接的socket,就可以对该socket进行读写操作。
客户端可以自己连自己,也可以两个客户端同时向对方发出请求建立连接,相同点在于没有服务端参与,也就没有listen,就能TCP建立连接。