~~网络编程(七):文件处理~~
进击のpython
网络编程——文件处理
有了上次的模板之后啊
我们就应该可以对于文件进行操作了
对于文件的操作就是上传和下载
而在上文上我也提到了,上文写的是一个模板
既然是模板,就应该是拿过来稍加改动就能完成我的要求
好,分析一下吧
在刚开始的时候是这样的
客户端键入命令
order = input() # get a.txt
然后把这条命令的字节形式,编码为gbk的形式传给服务端
phone.send(order.encode("gbk"))
然后服务端开始接收,并进行解码
order = phone.recv(1024)
filename = order.decode("gbk").split(" ")[1]
我拿到的就是想要下载的文件名
然后就进行报头的设计,就可以直接用模板
顺便说一下如何获取文件的大小?
os.path.getsize(文件名)
发完了报头就应该传输数据了是吧
因为字节才能在管道传输,所以我选择的打开方式是rb
打开文件之后,别一口气全读出来,万一很大呢?所以一行一行循环读
with open(filename,"rb") as f:
for i in f.read():
connet.send(i)
好了,这面发送了,你那面就该接收了吧
表面上是我把包丢给你了,实际上是你在原地新建了一个文件
然后把数据写入了
那我就在本地写个文件被,然后将收到的东西都写进来,怎么写?还是字节啊wb
with open(filename,"wb") as f:
recv_size = 0
while recv_size<re_len:
res = phone.recv(1024)
f.write(res)
recv_size+=len(res)
是吧!大约是这个套路吧
那整合一下吧
# 客户端
import json
import socket
# 买手机
import struct
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 拨号
phone.connect(("127.0.0.1", 8080))
# 发收信息
while 1:
order = input(">>>")
phone.send(order.encode("gbk"))
res = phone.recv(4)
re_msg = struct.unpack("i", res)[0]
msg = phone.recv(re_msg)
msg = msg.decode("gbk")
msg = json.loads(msg)
re_len = msg["file_size"]
re_size = 0
r = b"" # 我传过来的是字节模式
with open("b", "wb") as f:
recv_size = 0
while recv_size < re_len:
res = phone.recv(1024)
f.write(res)
recv_size += len(res)
print(f'打印成功')
connet.close()
# 关闭
phone.close()
# 服务端
import json
import os
import socket
import struct
import subprocess
# 买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定手机卡
phone.bind(("127.0.0.1", 8080))
phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 开机
phone.listen(5)
# 等电话
connet, client_addr = phone.accept()
# 收发消息
while 1:
try:
order = connet.recv(1024)
filename = order.decode("gbk").split(" ")[1]
# obj = subprocess.Popen(order.decode("gbk"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# stdout = obj.stdout.read()
# stderr = obj.stderr.read()
dic = {
"file_name": filename,
"MD5": "XXXXXXXXXXXXXXXX",
'file_size': os.path.getsize(filename)
}
head = json.dumps(dic)
head = head.encode("gbk")
res = struct.pack("i", len(head))
connet.send(res)
connet.send(head)
with open(filename) as f:
for line in f.read():
print(line)
connet.send(bytes(line, encoding="gbk"))
except ConnectionResetError:
break
# 挂电话
connet.close()
# 关机
phone.close()
但是你不觉得我写的太乱了吗??
所以,我们用函数写!
首先前面的全局变量是不适合放进函数里的是吧
而下面的代码块是不是都是执行语句
所以我们可以把这些代码整体进行缩进
def run():
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定手机卡
phone.bind(("127.0.0.1", 8080))
phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 开机
phone.listen(5)
# 等电话
connet, client_addr = phone.accept()
# 收发消息
while 1:
try:
order = connet.recv(1024)
filename = order.decode("gbk").split(" ")[1]
# obj = subprocess.Popen(order.decode("gbk"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# stdout = obj.stdout.read()
# stderr = obj.stderr.read()
dic = {
"file_name": filename,
"MD5": "XXXXXXXXXXXXXXXX",
'file_size': os.path.getsize(filename)
}
head = json.dumps(dic)
head = head.encode("gbk")
res = struct.pack("i", len(head))
connet.send(res)
connet.send(head)
with open(filename) as f:
for line in f.read():
print(line)
connet.send(bytes(line, encoding="gbk"))
except ConnectionResetError:
break
# 挂电话
connet.close()
# 关机
phone.close()
然后我们再来看,是不是中间有个下载的功能啊
然后我们默认传过来的命令是get是吧
所以这个是不是也可以封装成一个函数?
封装完之后是不是应该传参数啊
def down(connet, filename):
dic = {
"file_name": filename,
"MD5": "XXXXXXXXXXXXXXXX",
'file_size': os.path.getsize(filename)
}
head = json.dumps(dic)
head = head.encode("gbk")
res = struct.pack("i", len(head))
connet.send(res)
connet.send(head)
with open(filename) as f:
for line in f.read():
print(line)
connet.send(bytes(line, encoding="gbk"))
最后是不是应该再加个点睛之笔啊!
if __name__ == '__main__':
run()
那客户端是不是也可以封装函数啊
远离其实都差不多,就不再赘述了,直接放代码
def get(phone):
res = phone.recv(4)
re_msg = struct.unpack("i", res)[0]
msg = phone.recv(re_msg)
msg = msg.decode("gbk")
msg = json.loads(msg)
re_len = msg["file_size"]
with open("b", "wb") as f:
recv_size = 0
while recv_size < re_len:
res = phone.recv(1024)
f.write(res)
recv_size += len(res)
print(f'打印成功')
def run():
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
phone.connect(("127.0.0.1", 8080))
while 1:
order = input(">>>")
phone.send(order.encode("gbk"))
order = order.split()
if order[0] == "get":
get(phone)
phone.close()
最后一样,注入灵魂
if __name__ == '__main__':
run()
最后整理一下:
# 客户端
import json
import socket
# 买手机
import struct
def get(phone):
res = phone.recv(4)
re_msg = struct.unpack("i", res)[0]
msg = phone.recv(re_msg)
msg = msg.decode("gbk")
msg = json.loads(msg)
re_len = msg["file_size"]
with open("b.mp4", "wb") as f:
recv_size = 0
while recv_size < re_len:
res = phone.recv(1024)
f.write(res)
recv_size += len(res)
print(f'打印成功')
def put(phone):
pass
def run():
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
phone.connect(("127.0.0.1", 8080))
while 1:
order = input(">>>")
phone.send(order.encode("gbk"))
order = order.split()
if order[0] == "get":
get(phone)
elif order[0] == "put":
put(phone)
phone.close()
if __name__ == '__main__':
run()
# 服务端
import json
import os
import socket
import struct
import subprocess
def down(connet, filename):
dic = {
"file_name": filename,
"MD5": "XXXXXXXXXXXXXXXX",
'file_size': os.path.getsize(filename)
}
head = json.dumps(dic)
head = head.encode("gbk")
res = struct.pack("i", len(head))
print(len(head))
connet.send(res)
connet.send(head)
with open(filename, "rb") as f:
for line in f.readlines():
connet.send(line)
def put(connet, filename):
pass
def run():
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定手机卡
phone.bind(("127.0.0.1", 8080))
phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 开机
phone.listen(5)
# 等电话
connet, client_addr = phone.accept()
# 收发消息
while 1:
try:
order = connet.recv(1024)
filename = order.decode("gbk").split(" ")[1]
# obj = subprocess.Popen(order.decode("gbk"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# stdout = obj.stdout.read()
# stderr = obj.stderr.read()
if order.decode("gbk").split(" ")[0] == "get":
down(connet, filename)
elif order.decode("gbk").split(" ")[0] == "put":
put(connet, filename)
except ConnectionResetError:
break
# 挂电话
connet.close()
# 关机
phone.close()
if __name__ == '__main__':
run()
建议你们可以自己把另一个功能补上!
但是吧,其实这么写还不太好!
因为我们学过面向对象
所以我们也可以用面向对象来处理这个问题!
关于面向对象,就是将所有的方法进行打散,然后把每个方法都进行封装
最后自己调用自己写的方法就行
这一段就直接放代码了(关注一下反射的使用)
# 服务端
import socket
import struct
import json
import subprocess
import os
class MYTCPServer:
address_family = socket.AF_INET
socket_type = socket.SOCK_STREAM
allow_reuse_address = False
max_packet_size = 8192
coding='utf-8'
request_queue_size = 5
server_dir='file_upload'
def __init__(self, server_address, bind_and_activate=True):
"""Constructor. May be extended, do not override."""
self.server_address=server_address
self.socket = socket.socket(self.address_family,
self.socket_type)
if bind_and_activate:
try:
self.server_bind()
self.server_activate()
except:
self.server_close()
raise
def server_bind(self):
"""Called by constructor to bind the socket.
"""
if self.allow_reuse_address:
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind(self.server_address)
self.server_address = self.socket.getsockname()
def server_activate(self):
"""Called by constructor to activate the server.
"""
self.socket.listen(self.request_queue_size)
def server_close(self):
"""Called to clean-up the server.
"""
self.socket.close()
def get_request(self):
"""Get the request and client address from the socket.
"""
return self.socket.accept()
def close_request(self, request):
"""Called to clean up an individual request."""
request.close()
def run(self):
while True:
self.conn,self.client_addr=self.get_request()
print('from client ',self.client_addr)
while True:
try:
head_struct = self.conn.recv(4)
if not head_struct:break
head_len = struct.unpack('i', head_struct)[0]
head_json = self.conn.recv(head_len).decode(self.coding)
head_dic = json.loads(head_json)
print(head_dic)
#head_dic={'cmd':'put','filename':'a.txt','filesize':123123}
cmd=head_dic['cmd']
if hasattr(self,cmd):
func=getattr(self,cmd)
func(head_dic)
except Exception:
break
def put(self,args):
file_path=os.path.normpath(os.path.join(
self.server_dir,
args['filename']
))
filesize=args['filesize']
recv_size=0
print('----->',file_path)
with open(file_path,'wb') as f:
while recv_size < filesize:
recv_data=self.conn.recv(self.max_packet_size)
f.write(recv_data)
recv_size+=len(recv_data)
print('recvsize:%s filesize:%s' %(recv_size,filesize))
tcpserver1=MYTCPServer(('127.0.0.1',8080))
tcpserver1.run()
# 客户端
import socket
import struct
import json
import os
class MYTCPClient:
address_family = socket.AF_INET
socket_type = socket.SOCK_STREAM
allow_reuse_address = False
max_packet_size = 8192
coding='utf-8'
request_queue_size = 5
def __init__(self, server_address, connect=True):
self.server_address=server_address
self.socket = socket.socket(self.address_family,
self.socket_type)
if connect:
try:
self.client_connect()
except:
self.client_close()
raise
def client_connect(self):
self.socket.connect(self.server_address)
def client_close(self):
self.socket.close()
def run(self):
while True:
inp=input(">>: ").strip()
if not inp:continue
l=inp.split()
cmd=l[0]
if hasattr(self,cmd):
func=getattr(self,cmd)
func(l)
def put(self,args):
cmd=args[0]
filename=args[1]
if not os.path.isfile(filename):
print('file:%s is not exists' %filename)
return
else:
filesize=os.path.getsize(filename)
head_dic={'cmd':cmd,'filename':os.path.basename(filename),'filesize':filesize}
print(head_dic)
head_json=json.dumps(head_dic)
head_json_bytes=bytes(head_json,encoding=self.coding)
head_struct=struct.pack('i',len(head_json_bytes))
self.socket.send(head_struct)
self.socket.send(head_json_bytes)
send_size=0
with open(filename,'rb') as f:
for line in f:
self.socket.send(line)
send_size+=len(line)
print(send_size)
else:
print('upload successful')
client=MYTCPClient(('127.0.0.1',8080))
client.run()
好,最后这一种就是面向对象的写法了
至此,TCP就完事了,接下来就是UDP的天下了!