一、计算机基础
网络:
互联网协议
osi
- 七层: 应用层, 表, 会, 传输层, 网络层, 数据链层, 物理层
- 五层: 应用层(应用层, 表, 会), 传输层, 网络层, 数据链层, 物理层
五层协议详解:
-
物理层:
-
数据链路层: 以太网协议
2.1 ethernet规定: 一组电信号构成一个数据包,叫做‘帧’
每一数据帧分成:报头head和数据data两部分
head data
head包含:(固定18个字节)发送者/源地址,6个字节
接收者/目标地址,6个字节
数据类型,6个字节
data包含:(最短46字节,最长1500字节)数据包的具体内容
head长度+data长度=最短64字节,最长1518字节,超过最大限制就分片发送2.2 mac地址:
2.3 以太网工作方式: 基于mac地址的广播的方式来进行数据的传递(局域网内)
-
网络层:
ip协议: (ipv4, ipv6)
arp协议(了解): 把ip地址解析成Mac地址
-
传输层: tcp/udp(基于端口的协议)
-
应用层: (http协议/ftp协议)
tcp/udp协议详解:
-
tcp协议: 可靠协议(建立链接: 三次握手 断开链接: 四次挥手)
-
udp协议: 不可靠, 传输效率高, 网络开销低
socket:
- AF_UNIX
- AF_INET
服务器端: server_test.py
# -*- encoding: utf-8 -*-
"""
@author:
@license:
@contact:
@software:
@file: server_test.py
@time: 2020.8.7 11:47
@desc:
"""
import socket
# 1. 买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # SOCK_STREAM ---> tcp
print(phone)
# 2. 绑定手机卡(端口: 0-65535 其中0-2014给操作系统用)
phone.bind(('127.0.0.1', 8080))
# 3.开机
phone.listen(5)
# 4. 等待链接
print('starting....')
conn, client_addr = phone.accept()
print(conn, client_addr)
# 5. 收发消息
data = conn.recv(1024) # 单位是bytes 接收数据的最大数
print('客户端发到服务端的数据: ', data)
conn.send(data.upper())
# 6. 挂电话
conn.close()
# 7. 关机
phone.close()
客户端: client_test.py
# -*- encoding: utf-8 -*-
"""
@author:
@license:
@contact:
@software:
@file: client_test.py
@time: 2020.8.7 11:48
@desc:
"""
import socket
# 1. 买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # SOCK_STREAM ---> tcp
print(phone)
# 2. 拨号
phone.connect(('127.0.0.1', 8080))
# 3. 收发消息
phone.send('xxx'.encode('utf-8'))
data = phone.recv(1024)
print(data)
# 4. 关闭
phone.close()
在my_server.bind()之前加上如下代码, 重用端口
my_sever.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
加上链接循环
my_server.py
import socket
my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(5)
# 加上链接循环
while True:
client_conn, colient_addr = my_server.accept()
if not colient_addr:
my_server.close()
break
while True:
try:
res = client_conn.recv(1024)
if res.decode('utf-8') == 'exit' or not res:
client_conn.close()
break
client_conn.send(res.upper())
print(res.decode('utf-8'))
except ConnectionResetError:
break
消除不能接受空字符串的bug
my_client.py
import socket
my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
while True:
msg = input('>>> ').strip()
if not msg:continue # 消除不能接受空字符串的bug
my_client.send(msg.encode('utf-8'))
res = my_client.recv(1024)
print(res.decode('utf-8'))
if not res:
break
my_client.close()
模拟ssh远程执行命令
系统命令:
win: dir: 查看某一个文件夹下的子文件名与子文件夹 ipconfig: 查看本地网卡的ip信息 tasklist: 查看运行的进程
linux: ls ifconfig ps aux
执行系统命令: os模块 —> 在终端打印
sunbprocess —> 拿到返回结果
my_server.py
"""TODO 模拟ssh远程执行命令"""
import socket
import subprocess
my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(3)
while True:
client_conn, colient_addr = my_server.accept()
print(colient_addr)
# TODO
if not colient_addr:
my_server.close()
break
while True:
try:
# 1. 接收命令
cmd = client_conn.recv(1024).decode('utf-8')
if cmd == 'exit' or not cmd:
break
# 2. 执行命令, 拿到结果
obj = subprocess.Popen(cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout = obj.stdout.read()
stderr = obj.stderr.read()
# 3. 把明理路结果返回给客户端
client_conn.send(stdout + stderr) # 存在效率问题
except ConnectionResetError:
break
client_conn.close()
my_client.py
"""TODO 模拟ssh远程执行命令"""
import socket
my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
while True:
# 1. 发命令
cmd = input('>>> ').strip()
if not cmd:
continue
my_client.send(cmd.encode('utf-8'))
# 2. 拿到命令结果并打印
res = my_client.recv(1024) # 接收的数据可能超过1024个字节
print(res.decode('gbk'))
if not res:
break
my_client.close()
粘包现象
关闭已运行的python程序:
linux: pkill -9 python
win: taskkill python
send和recv:
-
send和recv都不会直接接收对方的数据, 而是操作自己的操作系统内存, 不是一个send对应一个recv
1.1 recv: wait data(耗时非常长), copy data
1.2 send: copy data
import struct
# 制作固定长度的报头
res = struct.pack('i', 123)
print(res, type(res), len(res))
"""b'{\x00\x00\x00' <class 'bytes'> 4"""
#
obj = struct.unpack('i', res)
print(obj, obj[0])
"""(123,) 123"""
解决粘包问题
my_server.py
"""TODO 模拟ssh远程执行命令"""
import struct
import socket
import json
import subprocess
my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(3)
while True:
client_conn, colient_addr = my_server.accept()
print(colient_addr)
# TODO
if not colient_addr:
my_server.close()
break
while True:
try:
# 1. 接收命令
cmd = client_conn.recv(1024).decode('utf-8')
if cmd == 'exit' or not cmd:
break
# 2. 执行命令, 拿到结果
obj = subprocess.Popen(cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout = obj.stdout.read()
stderr = obj.stderr.read()
# 3. 把命令结果返回给客户端
# 3.1 制作固定长度的报头
# send_count = len(stdout) + len(stderr)
# # header = struct.pack('i', send_count) # send_count的长度有限制
# header = struct.pack('l', send_count) # send_count的长度有限制
header_dic = {
'filename': 'a.txt',
'md5': 'xxxxx',
'total_size': len(stdout) + len(stderr)
}
header_json = json.dumps(header_dic)
header_bytes = header_json.encode('gbk')
# 3.2 发送报头的长度
client_conn.send(struct.pack('i', len(header_bytes)))
# 3.3 把报头数据发送给客户端
client_conn.send(header_bytes)
# 3.4 发送真实数据
count = 0
client_conn.send(stdout)
client_conn.send(stderr)
except ConnectionResetError:
break
client_conn.close()
my_client.py
"""TODO 模拟ssh远程执行命令"""
import socket
import struct
import json
my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
flag = True
while flag:
# 1. 发命令
cmd = input('>>> ').strip()
if not cmd:
continue
my_client.send(cmd.encode('utf-8'))
# 2. 拿到命令结果并打印
# 2.1 先收报头的长度
header_size = struct.unpack('i', my_client.recv(4))[0]
# 2.2 接收报头数据
header_bytes = my_client.recv(header_size)
# 2.3 从报头中解析出对真实数据的描述信息(数据的长度)
header_json = header_bytes.decode('gbk')
header_dic = json.loads(header_json)
recv_count = header_dic['total_size']
# 2.4 就收真实数据
count = 0
recv_data = b''
while count < recv_count:
res = my_client.recv(1024) # 接收的数据可能超过1024个字节
count += len(res)
recv_data += res
print(recv_data.decode('gbk'))
my_client.close()
my_server.py
"""TODO 文件上传下载功能"""
import struct
import socket
import json
import os
SERVER_PATH = r'E:\lufei\model_3\model_3_1\log\服务器端'
my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(3)
while True:
client_conn, colient_addr = my_server.accept()
print(colient_addr)
# TODO
if not colient_addr:
my_server.close()
break
while True:
try:
# 1. 接收命令
res = client_conn.recv(1024).decode('utf-8').split()
if res == 'exit' or not res:
break
# 2. 解析命令, 提取相应参数
file_name = res[1]
# 3. 以读的方式打开文件, 读取文件内容发送给客户端
# 3.1 制作固定长度的报头
header_dic = {
'filename': file_name,
'md5': 'xxxxx',
'file_size': os.path.getsize('%s\%s' % (SERVER_PATH, file_name))
}
header_json = json.dumps(header_dic)
header_bytes = header_json.encode('gbk')
# 3.2 发送报头的长度
client_conn.send(struct.pack('i', len(header_bytes)))
# 3.3 把报头数据发送给客户端
client_conn.send(header_bytes)
# 3.4 发送真实数据
with open('%s\%s' % (SERVER_PATH, file_name), 'rb') as f:
for line in f:
client_conn.send(line)
except ConnectionResetError:
break
client_conn.close()
my_client.py
"""TODO 文件下载上传功能"""
import socket
import struct
import json
CLIENT_PATH = r'E:\lufei\model_3\model_3_1\log\客户端'
my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
flag = True
while flag:
# 1. 发命令
cmd = input('>>> ').strip()
if not cmd:
continue
my_client.send(cmd.encode('utf-8'))
# 2. 以写的方式打开一个新文件, 将从服务端接收的文件内容写入客户端的新文件中
# 2.1 先收报头的长度
header_size = struct.unpack('i', my_client.recv(4))[0]
# 2.2 接收报头数据
header_bytes = my_client.recv(header_size)
# 2.3 从报头中解析出对真实数据的描述信息(数据的长度)
header_json = header_bytes.decode('gbk')
header_dic = json.loads(header_json)
recv_count = header_dic['file_size']
file_name = header_dic['filename']
# 2.4 接收真实数据
with open('%s\%s' % (CLIENT_PATH, file_name), 'wb') as f:
count = 0
while count < recv_count:
line = my_client.recv(1024) # 接收的数据可能超过1024个字节
count += len(line)
f.write(line)
my_client.close()
函数版本
my_server.py
"""TODO 文件上传下载功能"""
import struct
import socket
import json
import os
SERVER_PATH = r'E:\lufei\model_3\model_3_1\log\服务器端'
def get(client_conn, res):
file_name = res[1]
# 3. 以读的方式打开文件, 读取文件内容发送给客户端
# 3.1 制作固定长度的报头
header_dic = {
'filename': file_name,
'md5': 'xxxxx',
'file_size': os.path.getsize('%s\%s' % (SERVER_PATH, file_name))
}
header_json = json.dumps(header_dic)
header_bytes = header_json.encode('gbk')
# 3.2 发送报头的长度
client_conn.send(struct.pack('i', len(header_bytes)))
# 3.3 把报头数据发送给客户端
client_conn.send(header_bytes)
# 3.4 发送真实数据
with open('%s\%s' % (SERVER_PATH, file_name), 'rb') as f:
for line in f:
client_conn.send(line)
def run():
my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(3)
while True:
client_conn, colient_addr = my_server.accept()
print(colient_addr)
# TODO
if not colient_addr:
my_server.close()
break
while True:
try:
# 1. 接收命令
res = client_conn.recv(1024).decode('utf-8').split()
if res == 'exit' or not res:
break
# 2. 解析命令, 提取相应参数
if res[0] == 'get':
get(client_conn, res)
except ConnectionResetError:
break
client_conn.close()
if __name__ == '__main__':
run()
my_client.py
"""TODO 文件下载上传功能"""
import socket
import struct
import json
CLIENT_PATH = r'E:\lufei\model_3\model_3_1\log\客户端'
def get(my_client):
# 2. 以写的方式打开一个新文件, 将从服务端接收的文件内容写入客户端的新文件中
# 2.1 先收报头的长度
header_size = struct.unpack('i', my_client.recv(4))[0]
# 2.2 接收报头数据
header_bytes = my_client.recv(header_size)
# 2.3 从报头中解析出对真实数据的描述信息(数据的长度)
header_json = header_bytes.decode('gbk')
header_dic = json.loads(header_json)
recv_count = header_dic['file_size']
file_name = header_dic['filename']
# 2.4 接收真实数据
with open('%s\%s' % (CLIENT_PATH, file_name), 'wb') as f:
count = 0
while count < recv_count:
line = my_client.recv(1024) # 接收的数据可能超过1024个字节
count += len(line)
f.write(line)
def run():
my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
flag = True
while flag:
# 1. 发命令
inp = input('>>> ').strip()
if not inp:
continue
my_client.send(inp.encode('utf-8'))
cmds = inp.split()
if cmds[0] == 'get':
get(my_client)
my_client.close()
if __name__ == '__main__':
run()
一、计算机基础
网络:
互联网协议
osi
- 七层: 应用层, 表, 会, 传输层, 网络层, 数据链层, 物理层
- 五层: 应用层(应用层, 表, 会), 传输层, 网络层, 数据链层, 物理层
五层协议详解:
-
物理层:
-
数据链路层: 以太网协议
2.1 ethernet规定: 一组电信号构成一个数据包,叫做‘帧’
每一数据帧分成:报头head和数据data两部分
head data
head包含:(固定18个字节)发送者/源地址,6个字节
接收者/目标地址,6个字节
数据类型,6个字节
data包含:(最短46字节,最长1500字节)数据包的具体内容
head长度+data长度=最短64字节,最长1518字节,超过最大限制就分片发送2.2 mac地址:
2.3 以太网工作方式: 基于mac地址的广播的方式来进行数据的传递(局域网内)
-
网络层:
ip协议: (ipv4, ipv6)
arp协议(了解): 把ip地址解析成Mac地址
-
传输层: tcp/udp(基于端口的协议)
-
应用层: (http协议/ftp协议)
tcp/udp协议详解:
-
tcp协议: 可靠协议(建立链接: 三次握手 断开链接: 四次挥手)
-
udp协议: 不可靠, 传输效率高, 网络开销低
socket:
- AF_UNIX
- AF_INET
服务器端: server_test.py
# -*- encoding: utf-8 -*-
"""
@author:
@license:
@contact:
@software:
@file: server_test.py
@time: 2020.8.7 11:47
@desc:
"""
import socket
# 1. 买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # SOCK_STREAM ---> tcp
print(phone)
# 2. 绑定手机卡(端口: 0-65535 其中0-2014给操作系统用)
phone.bind(('127.0.0.1', 8080))
# 3.开机
phone.listen(5)
# 4. 等待链接
print('starting....')
conn, client_addr = phone.accept()
print(conn, client_addr)
# 5. 收发消息
data = conn.recv(1024) # 单位是bytes 接收数据的最大数
print('客户端发到服务端的数据: ', data)
conn.send(data.upper())
# 6. 挂电话
conn.close()
# 7. 关机
phone.close()
客户端: client_test.py
# -*- encoding: utf-8 -*-
"""
@author:
@license:
@contact:
@software:
@file: client_test.py
@time: 2020.8.7 11:48
@desc:
"""
import socket
# 1. 买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # SOCK_STREAM ---> tcp
print(phone)
# 2. 拨号
phone.connect(('127.0.0.1', 8080))
# 3. 收发消息
phone.send('xxx'.encode('utf-8'))
data = phone.recv(1024)
print(data)
# 4. 关闭
phone.close()
在my_server.bind()之前加上如下代码, 重用端口
my_sever.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
加上链接循环
my_server.py
import socket
my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(5)
# 加上链接循环
while True:
client_conn, colient_addr = my_server.accept()
if not colient_addr:
my_server.close()
break
while True:
try:
res = client_conn.recv(1024)
if res.decode('utf-8') == 'exit' or not res:
client_conn.close()
break
client_conn.send(res.upper())
print(res.decode('utf-8'))
except ConnectionResetError:
break
消除不能接受空字符串的bug
my_client.py
import socket
my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
while True:
msg = input('>>> ').strip()
if not msg:continue # 消除不能接受空字符串的bug
my_client.send(msg.encode('utf-8'))
res = my_client.recv(1024)
print(res.decode('utf-8'))
if not res:
break
my_client.close()
模拟ssh远程执行命令
系统命令:
win: dir: 查看某一个文件夹下的子文件名与子文件夹 ipconfig: 查看本地网卡的ip信息 tasklist: 查看运行的进程
linux: ls ifconfig ps aux
执行系统命令: os模块 —> 在终端打印
sunbprocess —> 拿到返回结果
my_server.py
"""TODO 模拟ssh远程执行命令"""
import socket
import subprocess
my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(3)
while True:
client_conn, colient_addr = my_server.accept()
print(colient_addr)
# TODO
if not colient_addr:
my_server.close()
break
while True:
try:
# 1. 接收命令
cmd = client_conn.recv(1024).decode('utf-8')
if cmd == 'exit' or not cmd:
break
# 2. 执行命令, 拿到结果
obj = subprocess.Popen(cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout = obj.stdout.read()
stderr = obj.stderr.read()
# 3. 把明理路结果返回给客户端
client_conn.send(stdout + stderr) # 存在效率问题
except ConnectionResetError:
break
client_conn.close()
my_client.py
"""TODO 模拟ssh远程执行命令"""
import socket
my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
while True:
# 1. 发命令
cmd = input('>>> ').strip()
if not cmd:
continue
my_client.send(cmd.encode('utf-8'))
# 2. 拿到命令结果并打印
res = my_client.recv(1024) # 接收的数据可能超过1024个字节
print(res.decode('gbk'))
if not res:
break
my_client.close()
粘包现象
关闭已运行的python程序:
linux: pkill -9 python
win: taskkill python
send和recv:
-
send和recv都不会直接接收对方的数据, 而是操作自己的操作系统内存, 不是一个send对应一个recv
1.1 recv: wait data(耗时非常长), copy data
1.2 send: copy data
import struct
# 制作固定长度的报头
res = struct.pack('i', 123)
print(res, type(res), len(res))
"""b'{\x00\x00\x00' <class 'bytes'> 4"""
#
obj = struct.unpack('i', res)
print(obj, obj[0])
"""(123,) 123"""
解决粘包问题
my_server.py
"""TODO 模拟ssh远程执行命令"""
import struct
import socket
import json
import subprocess
my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(3)
while True:
client_conn, colient_addr = my_server.accept()
print(colient_addr)
# TODO
if not colient_addr:
my_server.close()
break
while True:
try:
# 1. 接收命令
cmd = client_conn.recv(1024).decode('utf-8')
if cmd == 'exit' or not cmd:
break
# 2. 执行命令, 拿到结果
obj = subprocess.Popen(cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout = obj.stdout.read()
stderr = obj.stderr.read()
# 3. 把命令结果返回给客户端
# 3.1 制作固定长度的报头
# send_count = len(stdout) + len(stderr)
# # header = struct.pack('i', send_count) # send_count的长度有限制
# header = struct.pack('l', send_count) # send_count的长度有限制
header_dic = {
'filename': 'a.txt',
'md5': 'xxxxx',
'total_size': len(stdout) + len(stderr)
}
header_json = json.dumps(header_dic)
header_bytes = header_json.encode('gbk')
# 3.2 发送报头的长度
client_conn.send(struct.pack('i', len(header_bytes)))
# 3.3 把报头数据发送给客户端
client_conn.send(header_bytes)
# 3.4 发送真实数据
count = 0
client_conn.send(stdout)
client_conn.send(stderr)
except ConnectionResetError:
break
client_conn.close()
my_client.py
"""TODO 模拟ssh远程执行命令"""
import socket
import struct
import json
my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
flag = True
while flag:
# 1. 发命令
cmd = input('>>> ').strip()
if not cmd:
continue
my_client.send(cmd.encode('utf-8'))
# 2. 拿到命令结果并打印
# 2.1 先收报头的长度
header_size = struct.unpack('i', my_client.recv(4))[0]
# 2.2 接收报头数据
header_bytes = my_client.recv(header_size)
# 2.3 从报头中解析出对真实数据的描述信息(数据的长度)
header_json = header_bytes.decode('gbk')
header_dic = json.loads(header_json)
recv_count = header_dic['total_size']
# 2.4 就收真实数据
count = 0
recv_data = b''
while count < recv_count:
res = my_client.recv(1024) # 接收的数据可能超过1024个字节
count += len(res)
recv_data += res
print(recv_data.decode('gbk'))
my_client.close()
my_server.py
"""TODO 文件上传下载功能"""
import struct
import socket
import json
import os
SERVER_PATH = r'E:\lufei\model_3\model_3_1\log\服务器端'
my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(3)
while True:
client_conn, colient_addr = my_server.accept()
print(colient_addr)
# TODO
if not colient_addr:
my_server.close()
break
while True:
try:
# 1. 接收命令
res = client_conn.recv(1024).decode('utf-8').split()
if res == 'exit' or not res:
break
# 2. 解析命令, 提取相应参数
file_name = res[1]
# 3. 以读的方式打开文件, 读取文件内容发送给客户端
# 3.1 制作固定长度的报头
header_dic = {
'filename': file_name,
'md5': 'xxxxx',
'file_size': os.path.getsize('%s\%s' % (SERVER_PATH, file_name))
}
header_json = json.dumps(header_dic)
header_bytes = header_json.encode('gbk')
# 3.2 发送报头的长度
client_conn.send(struct.pack('i', len(header_bytes)))
# 3.3 把报头数据发送给客户端
client_conn.send(header_bytes)
# 3.4 发送真实数据
with open('%s\%s' % (SERVER_PATH, file_name), 'rb') as f:
for line in f:
client_conn.send(line)
except ConnectionResetError:
break
client_conn.close()
my_client.py
"""TODO 文件下载上传功能"""
import socket
import struct
import json
CLIENT_PATH = r'E:\lufei\model_3\model_3_1\log\客户端'
my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
flag = True
while flag:
# 1. 发命令
cmd = input('>>> ').strip()
if not cmd:
continue
my_client.send(cmd.encode('utf-8'))
# 2. 以写的方式打开一个新文件, 将从服务端接收的文件内容写入客户端的新文件中
# 2.1 先收报头的长度
header_size = struct.unpack('i', my_client.recv(4))[0]
# 2.2 接收报头数据
header_bytes = my_client.recv(header_size)
# 2.3 从报头中解析出对真实数据的描述信息(数据的长度)
header_json = header_bytes.decode('gbk')
header_dic = json.loads(header_json)
recv_count = header_dic['file_size']
file_name = header_dic['filename']
# 2.4 接收真实数据
with open('%s\%s' % (CLIENT_PATH, file_name), 'wb') as f:
count = 0
while count < recv_count:
line = my_client.recv(1024) # 接收的数据可能超过1024个字节
count += len(line)
f.write(line)
my_client.close()
函数版本
my_server.py
"""TODO 文件上传下载功能"""
import struct
import socket
import json
import os
SERVER_PATH = r'E:\lufei\model_3\model_3_1\log\服务器端'
def get(client_conn, res):
file_name = res[1]
# 3. 以读的方式打开文件, 读取文件内容发送给客户端
# 3.1 制作固定长度的报头
header_dic = {
'filename': file_name,
'md5': 'xxxxx',
'file_size': os.path.getsize('%s\%s' % (SERVER_PATH, file_name))
}
header_json = json.dumps(header_dic)
header_bytes = header_json.encode('gbk')
# 3.2 发送报头的长度
client_conn.send(struct.pack('i', len(header_bytes)))
# 3.3 把报头数据发送给客户端
client_conn.send(header_bytes)
# 3.4 发送真实数据
with open('%s\%s' % (SERVER_PATH, file_name), 'rb') as f:
for line in f:
client_conn.send(line)
def run():
my_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
my_server.bind(('127.0.0.1', 8081))
my_server.listen(3)
while True:
client_conn, colient_addr = my_server.accept()
print(colient_addr)
# TODO
if not colient_addr:
my_server.close()
break
while True:
try:
# 1. 接收命令
res = client_conn.recv(1024).decode('utf-8').split()
if res == 'exit' or not res:
break
# 2. 解析命令, 提取相应参数
if res[0] == 'get':
get(client_conn, res)
except ConnectionResetError:
break
client_conn.close()
if __name__ == '__main__':
run()
my_client.py
"""TODO 文件下载上传功能"""
import socket
import struct
import json
CLIENT_PATH = r'E:\lufei\model_3\model_3_1\log\客户端'
def get(my_client):
# 2. 以写的方式打开一个新文件, 将从服务端接收的文件内容写入客户端的新文件中
# 2.1 先收报头的长度
header_size = struct.unpack('i', my_client.recv(4))[0]
# 2.2 接收报头数据
header_bytes = my_client.recv(header_size)
# 2.3 从报头中解析出对真实数据的描述信息(数据的长度)
header_json = header_bytes.decode('gbk')
header_dic = json.loads(header_json)
recv_count = header_dic['file_size']
file_name = header_dic['filename']
# 2.4 接收真实数据
with open('%s\%s' % (CLIENT_PATH, file_name), 'wb') as f:
count = 0
while count < recv_count:
line = my_client.recv(1024) # 接收的数据可能超过1024个字节
count += len(line)
f.write(line)
def run():
my_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_client.connect(('127.0.0.1', 8081))
flag = True
while flag:
# 1. 发命令
inp = input('>>> ').strip()
if not inp:
continue
my_client.send(inp.encode('utf-8'))
cmds = inp.split()
if cmds[0] == 'get':
get(my_client)
my_client.close()
if __name__ == '__main__':
run()