文章目录
- 1、TCP/IP协议
- 2、Socket通信
- 3、基本通信知识
- 4、UDP网络收发数据
- 1、发送数据测试
- 2、接收数据测试
- 3、循环收发测试
- 5、TCP网络收发数据
- 1、基本原理和过程
- 2、数据收发示例-客户端
- 2、数据收发示例-服务器
本人不是计算机相关专业的,也没学过,本文仅代表我个人观点,很多理论部分也有很大一部分是个人理解,写下本文一方面是重在记录学习过程,一方面是为了方便自己平时查询。
1、TCP/IP协议
下面内容来自百度百科: TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP协议不仅仅指的是TCP 和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议。
总结:这个是一个用于网络间进行信息传输的一种协议。
协议分层,就像之前的在单片机Linux中的SPI,IIC协议一样,TCP/IP协议也有很多层,但是要比SPI,IIC这样的复杂多了,分层如下所示,这里我觉得是看看就行,了解下基本的含义就可以了。
各层的作用说明:
注:图源 TCP/IP协议详解
那么这个协议是如何进行通信的呢,解释如下:
网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。
其中TCP的协议还有比较有名的三次握手和四次挥手,我在学习的时候看到了,这里顺便记录下:
三次握手的过程
这里有人不太理解为什么要主机发送两次信号才能确认握手,这和我们平时不太一样,平时直接确定帧头帧尾就认为通信上了,下面的流程图给出了解释:
下面是四次挥手的流程图
当然实际情况下的通信不会是按照我们这样的过程的,这样肯定不太合适,总不能像流程图一样喊话吧,我要挥手,我要握手,这样肯定不行啊,实际上的传输是通过标志物来进行的。
标志位如下所示:
- SYN(synchronous) 建立联机
- ACK(acknowledgement) 确认
- PSH(push) 传输
- FIN(finish) 结束
- RST(reset) 重置
- URG(urgent) 紧急
关于标志位部分的的变化,可以看这个大佬的文章,写的比较清楚:四次挥手
2、Socket通信
前面的所有内容都没有讲socket,怎么就开始出现socket这个东西了呢,看起来确实有点突兀,明明说的是TCP/IP协议,这个协议的分支里面也都没有socket的内容,就是不明白这个socket和TCP/IP协议的关系
怎么理解呢,我的理解就是他是TCP/IP协议的抽象层,意思就是在代码上的表现形式
它是一组接口。他把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。Socket一般也称套接字,是一个网络通信的套接字(接口)。然后说了这些其实还是不懂,因为连套接字是什么都不知道。。。
所以还是看下面怎么让他进行通信吧!
在python中直接导入模块就可以创建了,命令如下所示:
import socket
socket.socket(address,type)
参数说明如下所示:
- address:可以选择 AF_INET(用于 Internet 进程间通信) 或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET
- type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)
因此我们现在就可以来创建TCP和UDP的socket了:
创建TCP的如下所示,中间部分省略,用来进行套接字的数据通信和一些功能配置使用的
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建TCP的套接字
sock.close() # 最后关掉
创建UDP的如下所示
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 创建UDP的套接字
sock.close() # 最后关掉
3、基本通信知识
一个比较基本的通信示例:
下面我进行一个比较基础的实验,使用socket进行通信对话,对话内容是每秒发送和接收一段内容,那么前面我们提到了进行通信需要三元组,这里也是一样的,需要的不能缺失掉,这里的三元组是IP地址,然后端口号,还有协议了,这里我们不用太注重协议,重点关注IP地址还有端口号。
首先是获取IP地址,这里注意是获取主机的IP地址,比如这里我设置电脑为主机,同样也用电脑作为从机吧,反正可以同时开多个python程序。
获取IP地址的命令如下,打开cmd,输入
ipconfig
电脑会显示我们的ip地址(该命令在linux中为ipconfig)
同时我们也可以看局域网下的一些其他设备,比如上面他说我们的网关(这里我用的手机热点)有一个IP地址,那想必就是手机的IP地址了,可以使用ping的命令来查看设备是否存在(这里也叫连通性测试),如下所示:
至于端口,端口的范围在(0-65535),端口一般就是通信的时候端口要对应下,其他的就是不要和一个比较常见的端口重合,比如80端口(局域网应该就没有这个问题),其他就没什么问题了,就是随便设置。
知名端口,一般就是一些公用的端口,范围0-1023,例如:
- 80端口分配给HTTP服务
- 21端口分配给FTP服务
一般我们临时建立的端口为动态端口,当我们的服务结束就意味着端口被释放了。
4、UDP网络收发数据
前面已经讲过了UDP和TCP套接字的使用流程,现在我们就先来试试效果,下面我用一张流程图先简要概括下UDP的通信过程:
1、发送数据测试
下面用一段代码来实验下,代码如下:
from socket import *
udp_socket = socket(AF_INET, SOCK_DGRAM) #创建套接字
dest_addr = ('192.168.218.133', 8080)
send_data = input("请输入要发送的数据:") # 这里获取要发送的数据
udp_socket.sendto(send_data.encode('utf-8'), dest_addr) # 数据发送
udp_socket.close() # 最后关闭
这里我们是当作客户端,那么服务器呢,可以我们在本机上写一个,当然也可以直接就是用现成的,用现成的这里使用网络调试助手就行了,这里我还是推荐VOFA,真是不错的好工具!
VOFA的配置如下所示:
我们可以开始运行程序,我们输入要发送的数据如下所示:
可以在VOFA这一端看到我们发送的数据内容(上面的内容是之前实验的时候发送的):
2、接收数据测试
上面已经测试发送数据,这里接收数据也是一样的,代码如下:
from socket import *
udp_socket = socket(AF_INET, SOCK_DGRAM)
dest_addr = ('192.168.218.133', 8080)
send_data = input("请输入要发送的数据:")
udp_socket.sendto(send_data.encode('utf-8'), dest_addr)
recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数
print(recv_data[0].decode('gbk')) # 接受的内容
print(recv_data[1]) # IP地址还有端口号
udp_socket.close()
3、循环收发测试
服务器这边创建一个套接字之后就绑定端口,之后不断进行轮询接收,接收内容非空就会回应数据了,一秒进行一次
**客户端这边也是,在创建套接字之后就连接端口,所以,一般来说服务器那边最好是先启动,这样方便客户端找到想要的内容,后面就是打印接收到的数据了,这里也是一秒一下
连接后如下所示:
这里注意下,就是上面的代码中有看到encode,decode,还有b’这样的字符,这其实是字符转码的意思,具体说明如下:
str->bytes:encode编码
bytes->str:decode解码
其中b’的作用和encode有点像,就是把字符转成二进制。
5、TCP网络收发数据
1、基本原理和过程
TCP和UDP相似,不过他比UDP在通信的过程上更加严格,这使得TCP更适合在一些传输过程要求更加更加严格的场合使用,TCP通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据。
所以总结来看,TCP就是打电话,是一对一的,UDP是广播,不用管有没有打开收音机去听,都会一直发送数据。
同时,TCP还是一种可靠传输,因为他对传输的要求严格,体现在:
-
TCP采用发送应答机制
TCP发送的每个报文段都必须得到接收方的应答才认为这个TCP报文段传输成功 -
超时重传
发送端发出一个报文段之后就启动定时器,如果在定时时间内没有收到应答就重新发送这个报文段,TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。 -
错误校验
TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。 -
流量控制和阻塞管理
流量控制用来避免主机发送得过快而使接收方来不及完全收下。
通信流程图如下所示:
2、数据收发示例-客户端
下面进行TCP数据发送的测试,这里首先测试本地程序模拟客户端的情况:
现将我们的VOFA设置为TCP服务端的模式
本地的代码如下所示:
from socket import *
tcp_client_socket = socket(AF_INET, SOCK_STREAM)
tcp_client_socket.connect(('192.168.218.133', 5555))
send_data = input("请输入要发送的数据:")
tcp_client_socket.send(send_data.encode("utf-8"))
recvData = tcp_client_socket.recv(1024)
print('接收到的数据为:', recvData.decode('utf-8'))
tcp_client_socket.close()
运行之后可以看到连接数量,同时我们发送过去还有返回的数据
可以看到程序这边打印返回的结果
2、数据收发示例-服务器
下面进行TCP数据发送的测试,这里测试本地程序模拟服务器的情况:
现将我们的VOFA设置为TCP客户端的模式
使用的测试代码如下所示
from socket import *
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
address = ('192.168.218.133', 7788)
tcp_server_socket.bind(address)
tcp_server_socket.listen(128)
client_socket, clientAddr = tcp_server_socket.accept()
recv_data = client_socket.recv(1024)
print('接收到的数据为:', recv_data.decode('gbk'))
client_socket.send("thank you !".encode('gbk'))
client_socket.close()
可以看到打开客户端后,收到数据就结束了,因为我们那边也只运行了一次就关闭了
这边打印出我们接收到的数据,为默认的一个握手数据
好的,这次就介绍到这里,后面还将继续分享相关内容!