计算机网路通讯:TCP/IP,UDP,Socket

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负责计算机间的通信,将包发送到接受者.
在这里插入图片描述

图 TCP报文格式

1.4 报文解析

序号报文结构描述
116位源端口号包含初始化通信的端口,源端口和源IP地址用于标识报文的返回地址
216位目的端口号定义传输的目的,表明报文接收计算机上的应用程序的地址接口
332位序号由接收端计算机使用,重新分段的报文转为最初形式,当SYN出现,序列码实际是初始序列码(Initial Sequence Number,ISN),而第一个数据字节是ISN+1,这个序列号可用于补偿传输中的不一致
432位确认序号由接收计算机使用,重组分段报文为最初形式,如果设置了ACK控制位,这个值表示一个准备接收包的序列号
54位首部长度TCP头大小,指示何处数据开始
6保留(6位)必须为0,为将来定义新的功能保留
7标志6位,分别为紧急标志(URG),有意义的应答标志(ACK),推(PSH),重置连接标志(RST),同步序列号标志(SYN),完成发送数据标志(FIN)
816位窗口大小表示想接收的每个TCP数据段的大小,TCP的流量控制由连接的每一端通过声明的窗口大小来提供,窗口大小为字节数,起始于确认号字段指明的值,这个值是接收端正期望接收的字节,窗口大小是一个16字节字段,因而窗口大小最大为65535字节.
916位校验和16位TCP头,源机器基于数据内容计算的一个值,收信机要与源机器数值结果完全一致,从而证明数据的有效性,检验和覆盖了整个的TCP报文段,这是一个强制性的字段,一定由发送端计算和存储,有接收端进行验证
1016位紧急指针指向后面是优先数据的字节,在URG标志设置的情况下才有效,如果URG标志位没有设置,紧急域作为补充,加快处理标识为紧急的数据段
11选项长度补丁,但长度为1字节,如果没有选项就表示这个字节与为0
12数据TCP协议包负载的数据

1.5 标志位解析

序号标志位描述
1URG紧急标志,为1时表明该位有效
2ACK确认标志,表明确认编号栏有效,多数情况下该标志位是置位的,TCP报头内的确认编号栏内包含的确认编号(w+1)为下一个预期的序列编号,同时提示远端系统已成功接收所有数据
3PSH推标志,该标志置位时,接收端不将该数据进行队列处理,二尽可能快地将数据转由应用处理,在处理Telnet或rlogin等交互模式连接时,该标志位总是置位的
4RST复位标志,用于复位相应的TCP连接
5SYN同步标志,表明同步序列号有效,该标志仅在三次握手建立TCP连接时有效,他提示TCP连接的服务端检查序列号,该序列号为TCP连接初始端(一般为客户端)的初始序列号
6FIN结束标志

1.6 TCP三次握手

在这里插入图片描述

图 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断开连接依旧是经历多次检验,这次是挥手告别,同样由客户端发起.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协议

用户数据报协议

持续更新ing

以上是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 openread/writeclose
模式操作,Socket即是一种特殊的文件,通过socket函数对其进行操作.

3.2 通信流程

socket

图 socket通信流程

服务端建立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建立与远程服务器的连接,从而实现客户端与服务器间的双向通信.
方法:

序号方法描述
1send向服务器发送数据
2close关闭websocket服务

【监听函数】

序号方法描述
1onopen当网络连接建立时触发该事件
2onerror当网络发生错误时触发事件
3onclose当websocket被关闭时触发事件
4onmessage当websocket客户端收到服务器发送的消息时的触发事件,数据提取:msg.data

【readyState属性】

序号方法描述
1CONNECTING(0)客户端正尝试与服务器建立连接
2OPEN(1)客户端正与服务器已建立连接
3CLOSING(2)客户端正与服务器断开连接
4CLOSED(3)客户端正与服务器已断开连接

WebSocket的url开头是ws,如需ssl加密,可使用wss;
新建websocket对象,即可实时通信.

# 127.0.0.1:8099/path为路由地址
socket = new WebSocket("ws://127.0.0.1:8099/path")
持续更新ing

5 总结

(1) TCP三次握手:
三次握手过程:

Created with Raphaël 2.2.0 开始 客户端通知服务端:我要连接你 服务端告知客户端:我知道你要连接我了 客户端告诉服务端:我知道你知道我要连接你了 结束:连接成功

(2) TCP四次挥手
四次挥手过程:

Created with Raphaël 2.2.0 开始 客户端通知服务端:我要离开你 服务端告知客户端:我知道你要离开我了 服务端告知客户端:我也要离开你 客户端告诉服务端:我知道你也要离开我 结束:断开成功

(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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天然玩家

坚持才能做到极致

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值