一 socket网络及差别介绍
TCP(传输控制协议)和UDP(用户数据报协议)是两种常见的互联网传输协议,它们之间有很多区别,包括以下几个主要方面:
1.1 TCP
TCP是传输控制协议,是面向连接的通讯协议(如:打电话),通过三次握手建立连接,通讯完成时四次挥手,一般应用在对安全性、完整性有严格要求的场景,如FTP、SMTP、HTTP等
- 优点:TCP 具有高可靠性,确保传输数据的正确性,不出现丢失或乱序
- 缺点:TCP相对于UDP速度慢一点,效率低,而且要求系统资源较多,每个连接都会占用系统的CPU、内存等硬件资源
1.2 UDP
UDP是用户数据报协议,是面向无连接的通讯协议(如:发短信)
- 优点:UDP速度快、操作简单、要求系统资源较少
- 缺点:不可靠,可能会出现丢包、乱序、数据不完整
1.3 TCP 与 UDP 的区别:
- 连接 TCP 是面向连接的传输层协议,传输数据前先要建立连接。UDP 是不需要连接,即刻传输数据。
- 服务对象 TCP 是一对一的两点服务,即一条连接只有两个端点。UDP 支持一对一、一对多、多对多的交互通信
- 可靠性 TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按序到达。UDP 是尽最大努力交付,不保证可靠交付数据。
- 拥塞控制、流量控制 TCP 有拥塞控制和流量控制机制,保证数据传输的安全性。UDP 则没有,即使网络非常拥堵了,也不会影响 UDP 的发送速率。
- 首部开销 TCP 首部长度较长,会有一定的开销,首部在没有使用「选项」字段时是 20 个字节,如果使用了「选项」字段则会变长的。UDP 首部只有 8 个字节,并且是固定不变的,开销较小,对系统资源要求较少。
- 实时性 UDP 具有较好的实时性,工作效率比 TCP 协议高。
1.4 应用场景
- 由于 TCP 是面向连接,能保证数据 的可靠性交付,因此经常用于:(20/21端口)FTP 文件传输、HTTP / HTTPS(80端口) 、SMTP(简单邮件传送协议)、TELNET(远程终端协议)
- 由于 UDP 面向无连接,它可以随时发送数据,再加上UDP本身的处理既简单又高效,因此经常用于:包总量较少的通信,如 DNS 、SNMP、TFTP(简单文件传输协议) 等、视频、音频等多媒体通信、广播通信
1.5 Socket数据传输方式
常用的有两种:
- SOCK_STREAM:表示面向连接的数据传输方式。数据可以准确无误地到达另一台计算机,如果损坏或丢失,可以重新发送,但效率相对较慢。常见的 http 协议就使用 SOCK_STREAM 传输数据,因为要确保数据的正确性,否则网页不能正常解析。针对于面向连接的TCP服务应用;
- SOCK_DGRAM:表示无连接的数据传输方式。计算机只管传输数据,不作数据校验,如果数据在传输中损坏,或者没有到达另一台计算机,是没有办法补救的。也就是说,数据错了就错了,无法重传。因为 SOCK_DGRAM 所做的校验工作少,所以效率比 SOCK_STREAM 高。对应于无连接的 UDP服务应用。
1.6 服务器端
from socket import *
server = socket(AF_INET, SOCK_DGRAM)
server_host_port = ('127.0.0.1', 6000) # 服务器的IP地址和端口
# 接收数据前绑定端口
server.bind(server_host_port)
while True:
# 接收数据
data = server.recvfrom(1024)
# print('data:', data) # (b'\xe4\xbd\xa0\xe5\xa5\xbd', ('127.0.0.1', 61328))
print('访问者:', data[0].decode('utf-8')) # 你好
# print(f'客户端的IP:{data[1][0]} \n客户端的端口:{data[1][1]}')
"""重新发送数据"""
send_data = input('客服说:')
server.sendto(send_data.encode('utf-8'), data[1])
# server.close()
1.7 客户端
from socket import *
client = socket(AF_INET, SOCK_DGRAM)
server_host_port = ('127.0.0.1', 6000) # 指定数据接收方
while True:
data = input('访问者:')
data = data.encode('utf-8')
client.sendto(data, server_host_port) # 发送数据
if data.decode('utf-8') == 'bye':
break
"""接收返回数据数据"""
recv_data = client.recvfrom(1024)
print(f"客服说:{recv_data[0].decode('utf-8')}")
print('程序关闭')
client.close()
二 UDP协议
udp的交互使用:sendto 和 recvfrom
SOCK_DGRAM:表示无连接的数据传输方式。计算机只管传输数据,不作数据校验,如果数据在传输中损坏,或者没有到达另一台计算机,是没有办法补救的。也就是说,数据错了就错了,无法重传。因为 SOCK_DGRAM 所做的校验工作少,所以效率比 SOCK_STREAM 高。对应于无连接的 UDP服务应用。
2.1 服务器代码
from socket import *
import struct
server_socket = socket(AF_INET, SOCK_DGRAM)
host_port = ('localhost', 8888) # 端口号
# 开始监听
server_socket.bind(host_port)
# 接收数据
data = server_socket.recvfrom(1024)
print(data, type(data))
# 解析操作码
recv_data = data[0]
new_data = struct.unpack('!H', recv_data[:2])
print('客户端请求的操作码:', new_data)
# 解析文件名
file_name = recv_data[2:-7].decode('utf-8')
print('客户端请求下载的文件名:', file_name)
server_socket.close()
2.2 客户端代码
from socket import *
import struct
client_socket = socket(AF_INET, SOCK_DGRAM)
host_port = ('localhost', 8888) # 端口号
file_name = input('请输入需要上传的文件名:').encode('utf-8')
print('file_name:', file_name, len(file_name))
data = struct.pack('!H%dsb5sb' % len(file_name), 1, file_name, 0, 'octet'.encode('utf-8'), 0)
# 发送数据
client_socket.sendto(data, host_port)
client_socket.close()
三 TCP协议
tcp的交互使用:send 和 recv
SOCK_STREAM:表示面向连接的数据传输方式。数据可以准确无误地到达另一台计算机,如果损坏或丢失,可以重新发送,但效率相对较慢。常见的 http 协议就使用 SOCK_STREAM 传输数据,因为要确保数据的正确性,否则网页不能正常解析。针对于面向连接的TCP服务应用;
3.1 TCP服务器代码
from socket import *
import random
# 创建SOCKET对象
server_socket = socket(AF_INET, SOCK_STREAM)
# 绑定IP和端口
host_port = ('', 6666) # 不写本机所有
server_socket.bind(host_port)
# 设置listen
server_socket.listen(5)
while True:
# 等待客户端连接
client_socket, addr = server_socket.accept()
print('客户端已连接,3次握手完成! ')
# print('client_socket:', client_socket)
# 接收数据
data = client_socket.recv(1024).decode('utf8')
print('data:', data)
oper_code = data.split(':')[0] # 操作码
recv_data = data.split(':')[1] # 需要上传和下载的文件
if oper_code == '1': # 下载操作
file_read = open(recv_data, 'r', encoding='utf8')
data = file_read.read()
# 将数据发给客户端
client_socket.send(data.encode('utf-8'))
file_read.close()
elif oper_code == '2': # 上传操作
file_write = open(str(random.randint(1000, 9999)) + '.txt', 'w', encoding='utf-8')
file_write.write(recv_data)
file_write.close()
print('服务器接收完成!')
elif oper_code == '0': # 已退出
print(recv_data)
3.2 客户端代码
from socket import *
while True:
client_socket = socket(AF_INET, SOCK_STREAM)
# 指定要连接的IP
host_port = ('127.0.0.1', 6666)
# 开始连接服务器
client_socket.connect(host_port)
choice = eval(input('请选择操作: 0.退出 1.下载 2.上传 \n'))
if choice == 1:
file_name = input('请输入要下载的文件名:')
# 告诉服务器要下载的文件名
join_data = (str(choice) + ':' + file_name).encode('utf-8')
# 发送数据
client_socket.send(join_data)
# 接收服务器返回的数据
recv_data = client_socket.recv(1024).decode('utf-8')
# 写入本地磁盘
download = open(file_name, 'w', encoding='utf-8')
download.write(recv_data)
download.close()
print('下载完成')
elif choice == 2: # 上传
path_name = input('请输入要上传的文件名:')
# 本地读取
upload = open(path_name, 'r', encoding='utf-8')
upload_data = upload.read()
# 拼接数据结构
data = (str(choice) + ':' + upload_data).encode('utf-8')
# 向服务器发送数据
client_socket.send(data)
upload.close()
print('数据上传成功!')
elif choice == 0:
# 告诉服务器已退出
client_socket.send((str(choice) + ':' + '客户端已退出').encode('utf-8'))
break
print('客户端关闭')
TCP连接时三次握手:
-
第一次:客户端向服务器端发送连接报文(SYN=1),同时选择一个初始序列号 seq=x,一起发送
-
第二次:服务器收到报文后向客户端发报文,确认报文为:(ACK=1,SYN=1),确认号为ack=x+1,同时服务器初始化一个序列号:seq=y,一起发送
-
第三次:客户端向服务器端发送报文(ACK=1),同时发送:ack=x+1,seq=y+1进行确认
TCP断开时四次挥手:开时四次挥手:
-
第一次:客户端发送释放报文并停止发送数据(FIN=1),带上序列号 seq=u,客户端进入终止等待状态(FIN-WAIT-1)
-
第二次:服务器收到报文后释放报文,发出确认报文(ACK=1,ack=u+1),并且带上序列号 seq=v,服务器进入关闭等待状态(CLOSE-WAIT)
-
第三次:服务器在数据传输完毕后发送连接释放报文(FIN=1,ack=u+1),同时发送序列号:seq=w,服务器进入最后确认状态(LAST-ACK)文章来源:https://www.toymoban.com/news/detail-730653.html
-
第四次:客户端收到释放报文后,向服务器发送报文(ACK=1,ack=w+1),发送序列号 seq=u+1,客户端进入时间等待状态(TIME-WAIT)。服务器接收到报文后直接关闭,客户端需要等2**MSL(最长报文段寿命)后结束文章来源地址https://www.toymoban.com/news/detail-730653.html
四 使用TCP传输较大的文件
4.1 服务端代码
from socket import *
import struct
server_socket = socket(AF_INET, SOCK_STREAM) # TCP
host_port = ('', 6666)
server_socket.bind(host_port)
server_socket.listen(1024)
# 开始监听
conn_socket, addr = server_socket.accept()
print('查看服务器接收到的请求地址:', addr)
# 接收数据
data_header = conn_socket.recv(4)
# 解包
size = struct.unpack('!i', data_header)[0]
print('size:', size)
# 将收到的数据上传到磁盘
file = open('a.pptx', 'wb')
recv_size = 0
while recv_size < size:
data_pack = conn_socket.recv(1024)
recv_size += len(data_pack)
file.write(data_pack)
file.close()
print('服务器接收完成')
conn_socket.close()
server_socket.close()
4.2 客户端代码
from socket import *
import os.path
import struct
client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect(('192.168.146.1', 6666))
# 发送内容
file_path = './111.pptx'
# 获取文件大小
size = os.path.getsize(file_path)
print('size:', size)
# 对struct数据进行打包
data = struct.pack('!i', size)
# 发送数据
client_socket.send(data)
file = open(file_path, 'rb')
# 循环读取 1024
while True:
data_pack = file.read(1024)
if not data_pack:
break
client_socket.send(data_pack) # 直接发
client_socket.close()
到了这里,关于Python 笔记02 (网络交互 TCP/UDP)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!