python socket 通信(发送文字、图片、文件)
本文使用 socket 来对文字、图片、文件进行通信,使其能够循环的接受和发送
1、IP/TCP/UDP简介
1.1、IP协议
互联网上每个计算机的唯一标识就是 IP 地址。IP 地址实际上是一个32位整数(称为IPv4),它是以字符串表示的 IP 地址,如:172.16.254.1,实际上是把32位整数按8位分组后得到的。如 图1.1.1所示:
图1.1.1 IPv4示例
IP 协议负责把数据从一台计算机通过网络发送到另一台计算机。数据被分割成一小块一小块。类似于将一个大包裹拆分成几个小包裹,然后通过 IP 包发送出去。
IP 包的特点是按块发送,途径多个路由,但不保证都能到达,也不能保证顺序到达。
1.2、TCP协议
TCP 协议是建立在 IP 协议之上的。TCP 协议负责在两台计算机之间建立可靠连接,保证数据包按顺序到达。TCP 协议会通过3次握手建立可靠连接。如 图1.2所示:
图 1.2.1 TCP 三次握手
传输时需要对每个 IP 包进行编号,确保对方按顺序收到,如果包丢掉了,就自动重发。如 图1.2.2所示:
图 1.2.2 传输数据包
一个 TCP 报文除了要包含传输的数据,还要包含源 IP 地址和目标 IP 地址、源端口和目标端口。每个网络程序都向操作系统申请唯一的端口号,这样两个进程在两台计算机之间建立网络连接就需要各自的 IP 地址和各自的端口号。
一个进程也可能同时与多个计算机建立连接,因此他会申请很多端口。端口号不是随意使用的,二十按照一定的规矩进行分配。例如:80端口分配给HTTP服务,21端口分配给FTP服务。
1.3、UDP协议
UDP 协议时面向无连接的协议。使用 UDP 协议时,不需要建立连接,子需要自动对方的 IP 地址和端口号,就可以直接发送数据包。但是无法保证数据一定到达。
虽然用 UDP 传输数据不可靠,但是它的有点是比 TCP 协议熟读快。对于不要求可靠到达的数据而言,就可以使用 UDP 协议。
TCP 协议和 UDP 协议的区别,如 图1.3.1所示:
图1.3.1 TCP协议和UDP协议的区别
2、socket简介
为了让两个程序通过网络进行通信,二者均必须使用 Socket 套接字。Socket 的英文原义是“孔”或“插座“,通常业称作”套接字“,用于描述 IP 地址和端口,它是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。如 图2.1所示:
图2.1 使用Socket实现通信
3、关键函数
s = socket.socket(AddressFamily,Type)
AddressFamily:可以选择 AF_INET(用于Internet进程间通信)或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用 AF_INET
Type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或则SOCK_DGRAM(数据包套接字,主要用于 UDP 协议)
# 创建TCP/IP套接字
tcpSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 创建UDP/IP套接字
udpSocket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
socket 对象的内置方法:
函数 | 描述 |
---|---|
s.bind() | 绑定地址(host,port)到套接字,在 AF_INET 下,以元组(host,port)的形式表示地址 |
s.listen() | 开始 TCP 监听。backlog 指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分要用程序设为5即可i |
s.accept() | 被动接受 TCP 客户端连接(阻塞式),等待连接的到来 |
s.connect() | 主动初始化 TCP 服务器连接,一般 address 的格式为元组(host,port),如果连接出错,返回 socket.error 错误 |
s.recv() | 接受 TCP 数据,数据以字符串 形式返回,bufsize 指定要接收的最大数据量,flag 提供有关消息的其他信息,通常可以忽略 |
s.send() | 发送 TCP 数据,将 string 中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小 |
s.sendall() | 完整发送 TCP 数据,将 string 中的数据发送到 连接的套接字,但在返回之前会尝试发送所有数据。成功返回 None,失败则抛出异常 |
s.recvfrom() | 接收 UDP 数据,与 recv() 类似,单返回值是(data,address)。其中 data 是包含接收数据的字符串,addrress 是发送数据的套接字 |
s.sendto() | 发送 UDP 数据,将数据发送到套接字,address 是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数 |
s.close() | 关闭套接字 |
4、发送文字
4.1、单次发送接收
客户端:
def SingleSendText():
"""
单次发送接收文字
"""
# host = socket.gethostname() # 获取主机地址 socket.gethostname()
host = "192.168.10.1" # 设置IP
port = 6666 # 设置端口号
tcpclient = socket.socket() # 创建TCP/IP套接字
tcpclient.connect((host, port)) # 主动初始化TCP服务器连接
print("已连接服务端")
send_data = input("请输入要发送的内容:")
tcpclient.send(send_data.encode()) # 发送TCP数据
info = tcpclient.recv(1024).decode()
print("接收到的内容:", info)
tcpclient.close()
服务端:
def SingleReceiveText():
"""
单次接收发送文字
"""
# host = socket.gethostname() # 获取主机地址 socket.gethostname()
host = "192.168.10.1" # 设置IP
port = 6666 # 设置端口号
tcpserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建TCP/IP套接字
tcpserver.bind((host, port)) # 绑定地址(host, port)到套接字
tcpserver.listen(5) # 设置最多连接数量
print("等待客户端连接...")
tcpclient, addr = tcpserver.accept() # 被动接收TCP客户端连接
print("客户端已经连接")
info = tcpclient.recv(1024).decode() # 接收客户端数据
print("接收到的内容:", info)
send_data = input("请输入要发送的内容:")
tcpclient.send(send_data.encode()) # 发送TCP数据
tcpclient.close()
tcpserver.close()
效果:
4..2、循环发送接收
客户端:
def CycleSendText():
"""
循环发送接收文字
"""
# host = socket.gethostname() # 获取主机地址 socket.gethostname()
host = "192.168.10.1" # 设置IP
port = 6666 # 设置端口号
tcpclient = socket.socket() # 创建TCP/IP套接字
tcpclient.connect((host, port)) # 主动初始化TCP服务器连接
print("已连接服务端")
while True: # 判断是否退出
send_data = input("请输入要发送的内容:")
tcpclient.send(send_data.encode()) # 发送TCP数据
if send_data == "byebye":
break
info = tcpclient.recv(1024).decode()
if info == "byebye":
break
else:
print("接收到的内容:", info)
tcpclient.close()
服务器:
def ReceiveTextCircularly():
"""
循环接收发送文字
"""
# host = socket.gethostname() # 获取主机地址 socket.gethostname()
host = "192.168.10.1" # 设置IP
port = 6666 # 设置端口号
tcpserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建TCP/IP套接字
tcpserver.bind((host, port)) # 绑定地址(host, port)到套接字
tcpserver.listen(5) # 设置最多连接数量
print("等待客户端连接...")
tcpclient, addr = tcpserver.accept() # 被动接收TCP客户端连接
print("客户端已经连接")
while True: # 判断是否退出
info = tcpclient.recv(1024).decode() # 接收客户端数据
if info == "byebye":
break
print("接收到的内容:", info)
send_data = input("请输入要发送的内容:")
tcpclient.send(send_data.encode()) # 发送TCP数据
if send_data == "byebye":
break
tcpclient.close()
tcpserver.close()
效果:
5、发送图片
5.1、单次发送接收
客户端:
def SingleSendPicture():
"""
单次发送图片
"""
host = "192.168.10.1" # 设置IP
port = 6666 # 设置端口号
tcpclient = socket.socket() # 创建TCP/IP套接字
tcpclient.connect((host, port)) # 主动初始化TCP服务器连接
print("已连接服务端")
imgPath = "people.jpg"
sdata = picture2base(imgPath)
print(f"开始发送图片 {imgPath}")
tcpclient.send(sdata.encode())
tcpclient.close()
print("发送完成")
服务端:
def SingleReceivePicture():
"""
单次接收图片
"""
host = "192.168.10.1" # 设置IP
port = 6666 # 设置端口号
tcpserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建TCP/IP套接字
tcpserver.bind((host, port)) # 绑定地址(host, port)到套接字
tcpserver.listen(5) # 设置最多连接数量
print("等待客户端连接...")
tcpclient, addr = tcpserver.accept() # 被动接收TCP客户端连接
print("客户端已经连接")
print("开始接收")
base64_data = ""
while True:
rdata = tcpclient.recv(1024)
base64_data += str(rdata, 'utf-8')
if not rdata:
break
base2picture(base64_data)
tcpclient.close()
tcpserver.close()
print("接收完成")
5.2、循环接收
客户端:
def CycleSendPictures():
"""
发送图片
"""
host = "192.168.10.1"
port = 6666
tcpclient = socket.socket()
tcpclient.connect((host, port))
print("已连接服务端")
imgPath = "people.jpg"
sdata = picture2base(imgPath)
print(f"开始发送图片 {imgPath}")
tcpclient.send(sdata.encode())
tcpclient.close()
print("发送完成")
服务端:
def ReceivePicturesCircularly():
"""
循环接收图片
"""
host = "192.168.10.1"
port = 6666
tcpserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpserver.bind((host, port))
tcpserver.listen(5)
print("等待客户端连接...")
while True:
tcpclient, addr = tcpserver.accept()
print("-"*5 + "开始接收" + "-"*5)
base64_data = ""
while True:
rdata = tcpclient.recv(1024)
base64_data += str(rdata, 'utf-8')
if not rdata:
break
base2picture(base64_data)
tcpclient.close()
print("-"*5 + "接收完成" + "-"*5)
tcpserver.close()
6、发送文件
客户端:
def SendFile():
"""发送文件"""
host = "192.168.10.1"
port = 6666
tcpclient = socket.socket()
try:
tcpclient.connect((host, port))
print('服务器已连接')
except:
print('服务器连接失败,请修改后重新运行!!')
exit(0)
while True:
print("-" * 5 + "开始发送" + "-" * 5)
filename = "qq.txt"
print(f"发送的文件为:{filename}")
with open(filename, "r", encoding="utf-8") as f:
rdata = f.read()
tcpclient.send("qq.txt".encode("utf-8"))
if tcpclient.recv(1024).decode("utf-8") == "ok":
while True:
tcpclient.send(rdata.encode('utf-8'))
break
print("-" * 5 + "发送完成" + "-" * 5)
break
tcpclient.close()
服务端:
def ReceivingFile():
"""
接收文件
"""
host = "192.168.10.1"
port = 6666
tcpserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpserver.bind((host, port))
tcpserver.listen(5)
print("等待客户端连接...")
while True:
tcpclient, addr = tcpserver.accept()
print('client addr:', addr)
while True:
print("-" * 5 + "开始接收" + "-" * 5)
fileNameData = tcpclient.recv(1024) # 接收文件名字
filename = fileNameData.decode('utf-8')
new_filename = "new_" + filename
print(f"文件保存为:{new_filename}")
if os.path.exists(new_filename):
os.remove(new_filename)
new_file = open(new_filename, "a", encoding="utf-8")
tcpclient.send("ok".encode("utf-8"))
while True:
rdata = tcpclient.recv(1024) # 接收文件内容
if not rdata:
break
new_file.write(rdata.decode("utf-8"))
new_file.close()
print("-" * 5 + "接收完成" + "-" * 5)
break
tcpclient.close()
# break # 注释则可以循环接收
tcpserver.close()
7、源码获取
更多推荐
所有评论(0)