~~网络编程(七):文件处理~~

进击の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的天下了!


*有点东西*
*继续深究*
原文地址:https://www.cnblogs.com/jevious/p/11327333.html