1 计算机网络
协议:通信双方遵循的控制信息交换的规则集合;
计算机网络体系结构是指计算机网络的分层,每一层应具有的功能及每层用到的协议的集合.
1.0 OSI-RM七层协议模型
序号 | 分层 | 描述 |
---|---|---|
1 | 应用层 | 实现多系统应用进程间的通信,是开放系统的最高层,直接为应用进程提供服务,http协议应用,短连接 |
2 | 表示层 | 指定数据读取标准,消除不同机器数据格式的读取障碍 |
3 | 会话层 | 建立并维持会话,同时维持会话同步 |
4 | 传输层 | 提供计算机间通讯数据传输服务,主要有TCP(长连接,客户端连接数量有限)和UDP两种协议 |
5 | 网络层 | 为分组交换网上的不同计算机提供通信服务 |
6 | 数据链路层 | 相邻节点传送数据时,数据链路层将网络层传来的IP数据组成帧,在两相邻节点的链路上传送帧 |
7 | 物理层 | 确定与传输媒体的接口有关的一些特性,如电气特性,机械特性 |
1.2 TCP/IP模型
序号 | 分层 | 描述 |
---|---|---|
1 | 应用层 | 应用层协议有TELNET,FTP,SMTP等,向用户提供一组常用的应用程序,如电子邮件,文件传输访问,远程登录等,远程登录TELNET使用TELNET协议提供在网络其它主机上注册的接口,TELNET会话提供了基于字符的虚拟终端,文件传输访问FTP使用FTP协议来提供网络内机器间的文件拷贝功能 |
2 | 传输层 | 提供应用程序间的通信,功能有格式化信息流,提供可靠传输,为实现可靠传输,传输层协议规定接收端必须发回确认,如分组丢失,必须重新发送,TCP及UDP协议 |
3 | 网络层 | 负责相邻计算机间的通信,提供通信服务,主要功能: 1处理来自传输层的分组发送请求,收到请求后,将分组装入IP数据报,填充报头,选择前往宿主机的路径,然后将数据报发往适当的网络接口 2处理输入数据报,首先检查其合法性,然后进行寻址,如过数据报已到达宿主及,则去掉报头,将剩下部分交给适当的传输协议,如果数据报未到达宿主机,则转发该数据报 3处理路径,流控和阻塞等问题 |
4 | 网络接口层 | TCP/IP软件的最底层,负责接收IP数据报并通过网络发送,或从网络上接收物理帧,抽出IP数据报,交给IP层 |
1.2.1 TCP协议
传输控制协议是一个工业标准的协议,用于应用程序间的通信,当应用程序通过TCP与另一个应用程序通信时,它会发送一个通信请求,这个请求必须被送到一个确切的地址,双方"握手"之后,TCP将两个应用程序之间建立一个全双工(full-duplex)通信.这个全双工的通信将占用两台计算机间的通信线路,直到被一方或双方关闭为止,是一种长连接,每次连接耗时较多.
- 特点
长连接.一次连接,连续发送多个数据包,每次数据收发后不断开连接,有数据传输时,直接发送即可,无需重新建立(三次握手)连接,但是客户端连接数量有限.
耗时多.每次连接,需要三次握手,需要时间.
1.2.2 IP协议
IP用于计算机间的通信,IP是无连接的通信协议,不会占用两个正在通信的计算机间的通信线路,因此IP降低了对网络线路的需求,每条线可同时满足许多不同计算机间的通信需要.通过IP消息(或其他数据)被分割为小的独立的包,通过因特网在计算机间传输,IP负责将每个包路由至他的目的地.
1.2.3 IP地址
每个计算机必须有一个IP地址才能接入因特网,每个IP包必须有一个地址才能发送到另一台计算机.网络上每个节点都必须有一个独立的IP地址,通常使用IPv4标准的IP地址为32bit,即4个字节,如0.0.0.0,每个字节为8位,共有256中选择,从0~255.IP地址由网路号和主机号构成.
1.3 TCP/IP解析
TCP/IP是一个协议族的统称,包括IP协议,IMCP协议,TCP协议,以及http,ftp,pop3协议等,协议即规则,按照规则传输数据,即可实现数据交换和交流信息.TCP负责应用程序(软件:如浏览器)和网络应用间的通信,将数据分割并装入IP包,然后在他们到达的时候重新组合.IP负责计算机间的通信,将包发送到接受者.
1.4 报文解析
序号 | 报文结构 | 描述 |
---|---|---|
1 | 16位源端口号 | 包含初始化通信的端口,源端口和源IP地址用于标识报文的返回地址 |
2 | 16位目的端口号 | 定义传输的目的,表明报文接收计算机上的应用程序的地址接口 |
3 | 32位序号 | 由接收端计算机使用,重新分段的报文转为最初形式,当SYN出现,序列码实际是初始序列码(Initial Sequence Number,ISN),而第一个数据字节是ISN+1,这个序列号可用于补偿传输中的不一致 |
4 | 32位确认序号 | 由接收计算机使用,重组分段报文为最初形式,如果设置了ACK控制位,这个值表示一个准备接收包的序列号 |
5 | 4位首部长度 | TCP头大小,指示何处数据开始 |
6 | 保留(6位) | 必须为0,为将来定义新的功能保留 |
7 | 标志 | 6位,分别为紧急标志(URG),有意义的应答标志(ACK),推(PSH),重置连接标志(RST),同步序列号标志(SYN),完成发送数据标志(FIN) |
8 | 16位窗口大小 | 表示想接收的每个TCP数据段的大小,TCP的流量控制由连接的每一端通过声明的窗口大小来提供,窗口大小为字节数,起始于确认号字段指明的值,这个值是接收端正期望接收的字节,窗口大小是一个16字节字段,因而窗口大小最大为65535字节. |
9 | 16位校验和 | 16位TCP头,源机器基于数据内容计算的一个值,收信机要与源机器数值结果完全一致,从而证明数据的有效性,检验和覆盖了整个的TCP报文段,这是一个强制性的字段,一定由发送端计算和存储,有接收端进行验证 |
10 | 16位紧急指针 | 指向后面是优先数据的字节,在URG标志设置的情况下才有效,如果URG标志位没有设置,紧急域作为补充,加快处理标识为紧急的数据段 |
11 | 选项 | 长度补丁,但长度为1字节,如果没有选项就表示这个字节与为0 |
12 | 数据 | TCP协议包负载的数据 |
1.5 标志位解析
序号 | 标志位 | 描述 |
---|---|---|
1 | URG | 紧急标志,为1时表明该位有效 |
2 | ACK | 确认标志,表明确认编号栏有效,多数情况下该标志位是置位的,TCP报头内的确认编号栏内包含的确认编号(w+1)为下一个预期的序列编号,同时提示远端系统已成功接收所有数据 |
3 | PSH | 推标志,该标志置位时,接收端不将该数据进行队列处理,二尽可能快地将数据转由应用处理,在处理Telnet或rlogin等交互模式连接时,该标志位总是置位的 |
4 | RST | 复位标志,用于复位相应的TCP连接 |
5 | SYN | 同步标志,表明同步序列号有效,该标志仅在三次握手建立TCP连接时有效,他提示TCP连接的服务端检查序列号,该序列号为TCP连接初始端(一般为客户端)的初始序列号 |
6 | FIN | 结束标志 |
1.6 TCP三次握手
客户端与服务端建立TCP连接经历三次握手(Three-Way Handshake),即建立一个TCP连接时,客户端和服务端共发送3个包以确认连接的建立,socket编程中,客户端使用connect函数触发.流程如图所示,解析如下:
序号 | 握手 | 描述 |
---|---|---|
1 | 第一次握手 | 客户端向服务器发起连接,将标志位SYN置位1,随机产生一个值seq=J,并将该数据包发送给服务端,客户端进入SYN_SENT状态,等待服务端确认 |
2 | 第二次握手 | 服务端收到客户端请求的数据包后,通过标志位SYN=1判断客户端请求建立连接,服务器将标志为SYN和ACK都置位1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给客户端以确认连接请求,服务端进入SYN_RCVD状态 |
3 | 第三次握手 | 客户端收到服务端发送的数据后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置位1,ack=K+1,并将数据包发送给服务端,服务端检查ack是否为K+1,ACK是否为1,如果正确,则连接建立成功,客户端和服务端进入ESTABLISED状态,完成三次握手,随后客户端和服务端间可以传输数据了 |
1.7 TCP四次挥手
客户端与服务端建立连接后,数据传输完成,需要断开连接,同样,TCP断开连接依旧是经历多次检验,这次是挥手告别,同样由客户端发起.TCP四次挥手告别(Four-Way Wavehand).
序号 | 挥手手 | 描述 |
---|---|---|
1 | 第一次挥手 | 客户端发送一个结束标志FIN,用于关闭客户端到服务端连接,此时客户端进入FIN_WAIT_1状态 |
2 | 第二次挥手 | 服务端收到FIN标志后,发送一个ACK给客户端,确认序列号为收到序号+1,与SYN相同,一个FIN占用一个序号,服务端进入CLOSE_WAIT状态 |
3 | 第三次挥手 | 服务端发送一个FIN,用来关闭服务端到客户端的连接,服务端进入LAST_ACK状态 |
4 | 第四次挥手 | 客户端接收到FIN后,随即进入TIME_WAIT状态,接着发送一个ACK给服务端,确认序列号为收到序列号+1, 服务端进入CLOSED状态,完成四次挥手 |
2 UDP协议
用户数据报协议
以上是TCP/IP的解析,接下来开介绍TCP/IP和UDP的高层封装使用:Scoket.
3 Socket
3.1 小序
Socket是应用层与传输层间的软件抽象层,是一组接口,实现网络进程中的通信.在设计模式中,Socket是一个门面模式,把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让socket组织数据,以符合指定的协议.
Socket起源于Unix,而Unix/Linux基本哲学之一是"一切皆文件",都可以用
o
p
e
n
↦
r
e
a
d
/
w
r
i
t
e
↦
c
l
o
s
e
open \mapsto read/write \mapsto close
open↦read/write↦close
模式操作,Socket即是一种特殊的文件,通过socket函数对其进行操作.
3.2 通信流程
服务端建立socket服务,绑定通信IP,并实时监听(阻塞到客户端接入)是否有客户端接入,若有客户端接入,则实现客户端与服务端进程间的通信.
3.3 一对一对话
一个服务端对一个客户端.
3.3.1服务端
#-*-coding:utf-8-*-
import socket
class SocketServer(object):
def server_test(self):
# streaming socket describe symbol
s = socket.socket()
# get host IP
host = socket.gethostname()
# set port
port = 8899
# address tuple
addr = (host, port)
# bind IP & Port
s.bind(addr)
# wait for client connection
s.listen(10)
# accept client connection & creat new socket describe symbol
client_socket, addr = s.accept()
print("Connected IP Address: {}".format(addr))
while True:
recv_bytes = client_socket.recv(1024)
recv_str = str(recv_bytes, encoding='utf-8')
if recv_str == 'q':
break
print("daqi> {}".format(recv_str))
send_msg = input("xiaoqi>")
send_bytes = bytes(send_msg, encoding='utf-8')
client_socket.sendall(send_bytes)
# s.close()
if __name__ == "__main__":
server = SocketServer()
server.server_test()
3.3.2 客户端:
#-*-coding:utf-8-*-
import socket
class SocketClient(object):
def client_test(self):
s = socket.socket()
# get host IP name
host = socket.gethostname()
port = 8899
addr = (host, port)
s.connect(addr)
while True:
send_msg = input("daqi>")
if send_msg == 'q':
break
send_bytes = bytes(send_msg, encoding='utf-8')
s.sendall(send_bytes)
print("successful sending")
rec_msg = s.recv(1024)
rec_str = str(rec_msg, encoding='utf-8')
print("xiaoqi: {}".format(rec_str))
print("successful received")
# s.close()
if __name__ == "__main__":
client = SocketClient()
client.client_test()
3.4 一对多对话:
一个服务端对多个可客户端.
3.4.1 服务端
from socketserver import BaseRequestHandler, ThreadingTCPServer
import threading
BUF_SIZE = 1024
class MultiServer(BaseRequestHandler):
def handle(self):
addr = self.client_address
print("IP Address: {}, Client connected success!".format(addr))
while True:
conn = self.request
rec_bytes = conn.recv(BUF_SIZE)
rec_str = str(rec_bytes, encoding='utf-8')
print("client:".format(rec_str))
cur_thread = threading.current_thread()
# send message
send_msg = input("robot>")
# send_msg = "xindaqi"
send_bytes = bytes(send_msg, encoding='utf-8')
conn.sendall(send_bytes)
if __name__ == "__main__":
host = "127.0.0.1"
port = 8080
addr = (host, port)
server = ThreadingTCPServer(addr, MultiServer)
print("Listening...")
server.serve_forever()
3.4.2 客户端
#-*-coding:utf-8-*-
import socket
class SocketClient(object):
def client_test(self):
s = socket.socket()
# get host IP name
# host = socket.gethostname()
host = "127.0.0.1"
port = 8080
addr = (host, port)
s.connect(addr)
print("Server connected!")
while True:
send_msg = input("daqi>")
if send_msg == 'q':
break
send_bytes = bytes(send_msg, encoding='utf-8')
s.sendall(send_bytes)
rec_msg = s.recv(1024)
rec_str = str(rec_msg, encoding='utf-8')
print("xiaoqi: {}".format(rec_str))
if __name__ == "__main__":
client = SocketClient()
client.client_test()
4 WebSocket
WebSocket是HTML5引入的新的通信协议,主要由Web客户端和服务器实现,WebSocket连接是客户端与服务器间永久的双向通信通道,全双工通信,可实现客户端和服务端的长连接,双向实时通信,其中任何一个都可以启动交换,一旦建立,连接一直有效,直到其中一方断开连接.
4.1 特点:
事件驱动,异步,使用ws或wss协议的客户端socket,能实现真正意义上的推送功能.
4.2 WebSocket客户端
WebSocket允许通过JavaScript建立与远程服务器的连接,从而实现客户端与服务器间的双向通信.
方法:
序号 | 方法 | 描述 |
---|---|---|
1 | send | 向服务器发送数据 |
2 | close | 关闭websocket服务 |
【监听函数】
序号 | 方法 | 描述 |
---|---|---|
1 | onopen | 当网络连接建立时触发该事件 |
2 | onerror | 当网络发生错误时触发事件 |
3 | onclose | 当websocket被关闭时触发事件 |
4 | onmessage | 当websocket客户端收到服务器发送的消息时的触发事件,数据提取:msg.data |
【readyState属性】
序号 | 方法 | 描述 |
---|---|---|
1 | CONNECTING(0) | 客户端正尝试与服务器建立连接 |
2 | OPEN(1) | 客户端正与服务器已建立连接 |
3 | CLOSING(2) | 客户端正与服务器断开连接 |
4 | CLOSED(3) | 客户端正与服务器已断开连接 |
WebSocket的url开头是ws,如需ssl加密,可使用wss;
新建websocket对象,即可实时通信.
# 127.0.0.1:8099/path为路由地址
socket = new WebSocket("ws://127.0.0.1:8099/path")
5 总结
(1) TCP三次握手:
三次握手过程:
(2) TCP四次挥手
四次挥手过程:
(3) 三次握手原因:服务器在监听状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端,告知客户端我知道你要链连接我,已经做好给客户端返回数据准备了;客户端接收到服务端做好准备后,再告知服务端,我知道你已做好准备,即将向你发送数据,这样,双方历经三个回合的确认,建立了可靠的连接.
(4) 四次挥手的原因:客户端通知服务端,我要和你断开连接,表明客户端不会再向服务端请求数据,但是此时的客户端还是可以接收数据的;服务端接收到客户端的断开请求后,告知客户端,我已知道你要断开,不会向你再发送数据,此时服务端向服务端发送断开确认,表明不会向客户端再发送数据,客户端接收服务端断开消息后,两者即可安全断开.
[参考文献]
[1]https://blog.csdn.net/Lao_tan/article/details/81428539
[2]https://www.cnblogs.com/wangcq/p/3520400.html
[3]https://www.cnblogs.com/aylin/p/5572104.html
[4]https://www.jianshu.com/p/ef892323e68f