2019-07-22 13:57:04 2365浏览
今天千锋扣丁学堂Python培训老师为大家分享一篇python中基于tcp协议的通信(数据传输)实例讲解,下面我们一起来看一下吧。
服务端:
from socket import *
# 确定服务端传输协议↓↓↓↓↓↓↓
server = socket(AF_INET, SOCK_STREAM) # 这里的SOCK_STREAM代表的就是流式协议TCP,如果是SOCK_DGRAM就代表UDP协议
# 固定服务端IP和PORT,让客户端能够通过IP和端口访问服务端↓↓↓↓↓↓↓
server.bind(('127.0.0.1', 8080)) # ('127.0.0.1', 8080)这里必须用元组形式传入IP和PORT,本地访问本地IP默认为'127.0.0.1'
# 设置半连接池数量(一般为5)
server.listen(5) # 半连接池:客户端连接请求个数的容器,当前已连接的客户端信息收发未完成前,会有最大5个客户端连接请求进入排队状态,
# 等待上一个通信完毕后,就可以连接进入开始通信。
# 双向通道建立成功,可以进行下一步数据的通信了↓↓↓↓↓↓↓
conn, client_addr = server.accept()
# 进行一次信息的收与发
data = conn.recv(1024) # 每次最大接收1024字节,收到的数据为二进制Bytes类型
conn.send(data.upper()) # 将收到的数据进行处理,返回新的数据,反馈给客户端(给客户端发数据),发的数据类型也必须是Bytes类型
# 一轮信息收发完毕,关闭已经建立的双向通道
conn.close()
客户端:
from socket import *
# 确定客户端传输协议↓↓↓↓↓↓↓(服务端和客户端服务协议一样才能进行有效的通信)
client = socket(AF_INET, SOCK_STREAM) # 这里的SOCK_STREAM代表的就是流式协议TCP,如果是SOCK_DGRAM就代表UDP协议
# 开始连接服务端IP和PORT,建立双向链接
client.connect(('127.0.0.1', 8080)) # 通过服务端IP和PORT进行连接
# 走到这一步就已经建立连接完毕,接下来开始数据通信:
client.send('hello,server'.encode('utf-8')) # 将发送的信息转码成Bytes类型数据
data = client.recv(1024) # 每次最大收数据大小为1024字节(1kb)
print(data.decode('utf-8')) # 将b类型数据转换成字符串格式
# 一次传输完毕
client.close() # 关闭客户端连接
启动服务端(服务端开始监听客户端的连接请求)
启动客户端(客户端给服务端发送连接请求)
建立双向链接完成
客户端给服务端发送信息 hello,server
服务端收到hello,server,将其转换成大写,返回给客户端(此时服务端一轮通信完毕)
客户端收到服务端的反馈信息,打印出HELLO,SERVER(此时客户端一轮通信完毕)
这个问题的更形象过程可以见下图:
服务端:
import socket
import struct
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
while True:
conn, client_addr = server.accept()
print('客户端已连接')
while True:
try:
head = conn.recv(4)
size = struct.unpack('i', head)[0]
data = conn.recv(size)
print('已收到客户端信息:', data.decode('utf-8'))
except ConnectionResetError:
print('客户端已中断连接')
conn.close()
break
客户端:
import socket
import struct
while True:
try:
client = socket.socket()
client.connect(('127.0.0.1', 8080))
print('已连接到服务端')
while True:
try:
msg = 'abcdefghijklmnopqrstuvwxyz1234567890'.encode('utf-8')
head = struct.pack('i', len(msg))
client.send(head)
client.send(msg)
except ConnectionResetError:
print('服务端已中断连接')
client.close()
break
except ConnectionRefusedError:
print('无法连接到服务器')
下载服务端:
import socket
import time
import struct
import json
# 计算当前文件夹下文件的md5值、大小
import os, hashlib
def get_info(file_name):
file_info = {}
base_dir = os.path.dirname(__file__)
file_dir = os.path.join(base_dir, file_name)
if os.path.exists(file_dir):
# md5计算时文件数据是放在内存中的,当我们计算一个大文件时,可以用update方法进行分步计算,
# 每次添加部分文件数据进行计算,减少内存占用。
with open(file_dir, 'rb') as f:
le = 0
d5 = hashlib.md5()
for line in f:
le += len(line)
d5.update(line)
file_info['lenth'] = le # 将文件长度加入报头字典
file_md5 = d5.hexdigest()
file_info['md5'] = file_md5 # 将文件md5加入报头字典
file_size = os.path.getsize(file_dir) / float(1024 * 1024)
file_info['size(MB)'] = round(file_size, 2) # 将文件大小加入报头字典
return file_info
else:
return file_info
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
while True:
conn, client_addr = server.accept()
print('%s >:客户端(%s)已连接' % (time.strftime('%Y-%m-%d %H:%M:%S'), client_addr))
while True:
try:
download_filename = conn.recv(1024).decode('utf-8')
download_file_info_dic = get_info(download_filename)
j_head = json.dumps(download_file_info_dic) # 将文件信息字典转成json字符串格式
head = struct.pack('i', len(j_head))
conn.send(head)
conn.send(j_head.encode('utf-8'))
if not download_file_info_dic:
continue
with open(download_filename, 'rb') as f:
while True:
data=f.read(1024)
conn.send(data)
# for line in f:
# conn.send(line)
except ConnectionResetError:
print('%s >:客户端(%s)已断开' % (time.strftime('%Y-%m-%d %H:%M:%S'), client_addr))
conn.close()
break
下载客户端:
import socket
import time
import struct
import json
# 进度条显示
def progress(percent,width=30):
text=('\r[%%-%ds]'%width)%('x'*int(percent*width))
text=text+'%3s%%'
text=text%(round(percent*100))
print(text,end='')
while True:
try:
client = socket.socket()
client.connect(('127.0.0.1', 8080))
print('%s >:已连接到服务端' % time.strftime('%Y-%m-%d %H:%M:%S'))
while True:
try:
file_name = input('请输入下载文件名称:')
client.send(file_name.encode('utf-8'))
head = client.recv(4) # 收报头
j_dic_lenth = struct.unpack('i', head)[0] # 解压报头,获取json格式的文件信息字典的长度
j_head = client.recv(j_dic_lenth) # 收json格式的信息字典
file_info_dic = json.loads(j_head) # 反序列化json字典,得到文件信息字典
if not file_info_dic:
print('文件不存在')
continue
file_lenth = file_info_dic.get('lenth')
file_size = file_info_dic.get('size(MB)')
file_md5 = file_info_dic.get('md5')
rec_len = 0
with open('cpoy_'+file_name, 'wb') as f:
while rec_len < file_lenth:
data = client.recv(1024)
f.write(data)
rec_len += len(data)
per=rec_len/file_lenth
progress(per)
print()
# print('下载比例:%6s %%'%)
if not rec_len:
print('文件不存在')
else:
print('文件[%s]下载成功: 大小:%s MB|md5值:[%s]' % (file_name, file_size, file_md5))
except ConnectionResetError:
print('%s >:服务端已终止' % time.strftime('%Y-%m-%d %H:%M:%S'))
client.close()
break
except ConnectionRefusedError:
print('%s >:无法连接到服务器' % time.strftime('%Y-%m-%d %H:%M:%S'))
服务端:
import socketserver
import time
class MyTcpHandler(socketserver.BaseRequestHandler):
# 到这里表示服务端已监听到一个客户端的连接请求,将通信交给一个handle方法实现,自己再去监听客户连接请求
def handle(self):
# 建立双向通道,进行通信
print('%s|客户端%s已连接' % (time.strftime('%Y-%m-%d %H:%M:%S'), self.client_address))
while True:
try:
data = self.request.recv(1024)
msg = '我已收到您的请求[%s],感谢您的关注!' % data.decode('utf-8')
self.request.send(msg.encode('utf-8'))
except ConnectionResetError:
print('%s|客户端%s已断开连接' % (time.strftime('%Y-%m-%d %H:%M:%S'), self.client_address))
break
if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyTcpHandler) # 绑定服务端IP和PORT,并产生并发方法对象
print('等待连接请求中...')
server.serve_forever() # 服务端一直开启
客户端:
from socket import *
import time
server_addr = ('127.0.0.1', 8080)
count = 1
while True:
if count > 10:
time.sleep(1)
print('%s|连接%s超时' % (time.strftime('%Y-%m-%d %H:%M:%S'), server_addr))
break
try:
client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 8080))
count = 1
print('%s|服务端%s连接成功' % (time.strftime('%Y-%m-%d %H:%M:%S'), server_addr))
while True:
try:
client.send('北鼻'.encode('utf-8'))
data = client.recv(1024)
print(data.decode('utf-8'))
time.sleep(0.5)
except ConnectionResetError:
print('%s|服务端%s已中断' % (time.strftime('%Y-%m-%d %H:%M:%S'), server_addr))
client.close()
break
except ConnectionRefusedError:
print('无法连接到服务端')
count += 1
服务端
import socketserver
import struct
import subprocess
class MyTcpHandler(socketserver.BaseRequestHandler):
def handle(self):
while True:
print('客户端<%s,%s>已连接' % self.client_address)
try:
cmd = self.request.recv(1024).decode('utf-8')
res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout = res.stdout.read()
stderr = res.stderr.read()
head = struct.pack('i', len(stdout + stderr))
self.request.send(head)
self.request.send(stdout)
self.request.send(stderr)
except ConnectionResetError:
print('客户端<%s,%s>已中断连接' % self.client_address)
self.request.close()
break
if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyTcpHandler)
server.serve_forever()
客户端
from socket import *
import struct
while True:
try:
client = socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1', 8080))
while True:
try:
cmd = input('>>>>>>>:').strip().encode('utf-8')
client.send(cmd)
head = client.recv(4)
size = struct.unpack('i', head)[0]
cur_size = 0
result = b''
while cur_size < size:
data = client.recv(1024)
cur_size += len(data)
result += data
print(result.decode('gbk')) # windows系统默认编码是gbk,解码肯定也要用gbk
except ConnectionResetError:
print('服务端已中断')
client.close()
break
except ConnectionRefusedError:
print('无法连接服务端')
【关注微信公众号获取更多学习资料】 【扫码进入Python全栈开发免费公开课】