网络编程

文件传输:

     1.简单版本   服务端

 1 import subprocess
 2 import socket
 3 import struct
 4 import json
 5 import os
 6 
 7 share_dir = r'D:路飞学城练习与作业pycharm练习6.网络编程5.文件传输简单版本servershare'  # r 取消特殊符号的意思 应该写到配置文件中
 8 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 9 phone.bind(('127.0.0.1',8080))
10 phone.listen(5)
11 print('strating...')
12 while True:
13     conn,client_addr = phone.accept()
14     print(client_addr)
15 
16     while True:
17         try:
18             # 1.收命令
19             res = conn.recv(8096) # b'get a.txt'
20             if not res:break
21             print('客户端数据:',res)
22 
23             # 2.解析命令 提取相应的命令参数
24             cmds = res.decode('utf-8').split()
25             filename = cmds[1]
26 
27             # 3.以读的方式打开文件,读取文件内容 发送给客户端  不知道文件的大小 还是用header_dic
28             # 第一步:制作固定长度的报头  # 将字典转成 str 转成 bytes  用到了序列化
29             header_dic = {
30                 'filename':filename,
31                 'md5':'xxxxxxx',
32                 'file_size': os.path.getsize('%s/%s'%(share_dir,filename))
33             }
34             header_json = json.dumps(header_dic)
35             header_bytes = header_json.encode('utf-8')   # 这里不知道 多长 会粘包!!
36 
37             # 第二步先发送报头的长度
38             conn.send(struct.pack('i',len(header_bytes)))
39 
40             # 第三步:再发报头
41             conn.send(header_bytes)
42 
43             # 第四部:在发真实的数据
44             with open('%s/%s'%(share_dir,filename),'rb') as f:
45                 # conn.send(f.read()) 一下读出来 有可能文件 很大
46                 for line in f:
47                     conn.send(line)  # 会粘包 连续好多个send 和一下发过去 一样的道理 但是节省内存
48 
49         except ConnectionResetError:
50             break
51     conn.close()
52 
53 phone.close()

    1.简单版本   客户端

 1 # -*- coding:utf-8 -*-
 2 '''
 3 思路:
 4     1.处理报头 准备发送的字典 先发报头的长度 再收报头 得到数据的长度 在收数据
 5     做字典 能容纳 很多信息量
 6     解决了:1.报头信息量少 2.i 格式有限的 解决了
 7 '''
 8 import json
 9 import socket
10 import struct
11 
12 download_dir = r'D:路飞学城练习与作业pycharm练习6.网络编程5.文件传输简单版本clientdownload' # 应该写到配置文件中
13 
14 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
15 phone.connect(('127.0.0.1',8080))
16 
17 while True:
18     # 1.发命令
19     cmd = input('msg>>>:').strip()  # get a.txt 软件自己定义的 格式
20     if not cmd:continue
21     phone.send(cmd.encode('utf-8'))
22 
23     # 2.以写的方式打开一个新文件,接收服务端发来的文件内容写入客户的新文件
24     # 第一步 先收报头的长度
25     obj = phone.recv(4)
26     header_size = struct.unpack('i',obj)[0]
27 
28     # 第二步:在收报头
29     header_bytes = phone.recv(header_size)
30 
31     # 第三步:从报头中解析出对真实数据的描述
32     header_json = header_bytes.decode('utf-8')
33     header_dic = json.loads(header_json)
34     print(header_dic)
35     total_size = header_dic['file_size']
36     filename = header_dic['filename']
37 
38     # 第四步:接收真实的数据
39     with open('%s/%s'%(download_dir,filename),'wb') as f: # filename wb 瞬间清掉
40         recv_size = 0
41         while recv_size < total_size:
42             line = phone.recv(1024)
43             f.write(line)
44             recv_size+=len(line)
45             print('总大小:%s 已下载:%s'%(total_size,recv_size))  # 这里应该有个进度条 提示用户
46 
47 phone.close()

  2.优化版本   服务端

 1 import subprocess
 2 import socket
 3 import struct
 4 import json
 5 import os
 6 
 7 share_dir = r'D:路飞学城练习与作业pycharm练习6.网络编程5.文件传输优化版本servershare'  # r 取消特殊符号的意思 应该写到配置文件中
 8 
 9 
10 def get(conn,cmds):
11     filename = cmds[1]
12 
13     # 3.以读的方式打开文件,读取文件内容 发送给客户端  不知道文件的大小 还是用header_dic
14     # 第一步:制作固定长度的报头  # 将字典转成 str 转成 bytes  用到了序列化
15     header_dic = {
16         'filename': filename,
17         'md5': 'xxxxxxx',
18         'file_size': os.path.getsize('%s/%s' % (share_dir, filename))
19     }
20     header_json = json.dumps(header_dic)
21     header_bytes = header_json.encode('utf-8')  # 这里不知道 多长 会粘包!!
22 
23     # 第二步先发送报头的长度
24     conn.send(struct.pack('i', len(header_bytes)))
25 
26     # 第三步:再发报头
27     conn.send(header_bytes)
28 
29     # 第四部:在发真实的数据
30     with open('%s/%s' % (share_dir, filename), 'rb') as f:
31         # conn.send(f.read()) 一下读出来 有可能文件 很大
32         for line in f:
33             conn.send(line)  # 会粘包 连续好多个send 和一下发过去 一样的道理 但是节省内存
34 
35 def put():
36     pass
37 
38 def run():
39     phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
40     phone.bind(('127.0.0.1',8080))
41     phone.listen(5)
42     print('strating...')
43     while True:
44         conn,client_addr = phone.accept()
45         print(client_addr)
46 
47         while True:
48             try:
49                 # 1.收命令
50                 res = conn.recv(8096) # b'get a.txt'
51                 if not res:break
52                 print('客户端数据:',res)
53 
54                 # 2.解析命令 提取相应的命令参数
55                 cmds = res.decode('utf-8').split()
56                 if cmds[0] == 'get':
57                     get(conn,cmds)
58                 elif cmds[0] == 'put':
59                     put(conn,cmds)
60 
61 
62             except ConnectionResetError:
63                 break
64         conn.close()
65 
66     phone.close()
67 
68 if __name__ == "__main__":
69     run()

  2.优化版本   客户端

 1 # -*- coding:utf-8 -*-
 2 '''
 3 思路:
 4     1.处理报头 准备发送的字典 先发报头的长度 再收报头 得到数据的长度 在收数据
 5     做字典 能容纳 很多信息量
 6     解决了:1.报头信息量少 2.i 格式有限的 解决了
 7 '''
 8 import json
 9 import socket
10 import struct
11 
12 download_dir = r'D:路飞学城练习与作业pycharm练习6.网络编程5.文件传输优化版本clientdownload' # 应该写到配置文件中
13 
14 def get(phone,cmds):
15     # 2.以写的方式打开一个新文件,接收服务端发来的文件内容写入客户的新文件
16     # 第一步 先收报头的长度
17     obj = phone.recv(4)
18     header_size = struct.unpack('i', obj)[0]
19 
20     # 第二步:在收报头
21     header_bytes = phone.recv(header_size)
22 
23     # 第三步:从报头中解析出对真实数据的描述
24     header_json = header_bytes.decode('utf-8')
25     header_dic = json.loads(header_json)
26     print(header_dic)
27     total_size = header_dic['file_size']
28     filename = header_dic['filename']
29 
30     # 第四步:接收真实的数据
31     with open('%s/%s' % (download_dir, filename), 'wb') as f:  # filename wb 瞬间清掉
32         recv_size = 0
33         while recv_size < total_size:
34             line = phone.recv(1024)
35             f.write(line)
36             recv_size += len(line)
37             print('总大小:%s 已下载:%s' % (total_size, recv_size))  # 这里应该有个进度条 提示用户
38 
39 def put(phone,cmds):
40     pass
41 
42 def run():
43     phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
44     phone.connect(('127.0.0.1',8080))
45 
46     while True:
47         # 1.发命令
48         inp = input('msg>>>:').strip()  # get a.txt 软件自己定义的 格式
49         if not inp:continue
50         phone.send(inp.encode('utf-8'))
51 
52         cmds = inp.split()
53         if cmds[0] == 'get':
54             get(phone,cmds)
55         elif cmds[0] == 'put':
56             put(phone,cmds)
57 
58     phone.close()  
59 
60 if __name__ == "__main__":
61     run()

  

 3.面向对象版本  服务端

  1 import socket
  2 import os
  3 import struct
  4 import pickle
  5 
  6 
  7 class TCPServer:
  8     address_family = socket.AF_INET
  9     socket_type = socket.SOCK_STREAM
 10     listen_count = 5
 11     max_recv_bytes = 8192
 12     coding = 'utf-8'
 13     allow_reuse_address = False
 14     # 下载的文件存放路径
 15     down_filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'share')
 16     # 上传的文件存放路径
 17     upload_filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'upload')
 18 
 19     def __init__(self,server_address,bind_and_listen=True):
 20         self.server_address = server_address
 21         self.socket = socket.socket(self.address_family,self.socket_type)
 22 
 23         if bind_and_listen:
 24             try:
 25                 self.server_bind()
 26                 self.server_listen()
 27             except Exception:
 28                 self.server_close()
 29 
 30     def server_bind(self):
 31         if self.allow_reuse_address:
 32             self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
 33         self.socket.bind(self.server_address)
 34 
 35     def server_listen(self):
 36         self.socket.listen(self.listen_count)
 37 
 38     def server_close(self):
 39         self.socket.close()
 40 
 41     def server_accept(self):
 42         return self.socket.accept()
 43 
 44     def conn_close(self,conn):
 45         conn.close()
 46 
 47     def run(self):
 48         print('starting...')
 49         while True:
 50             self.conn,self.client_addr = self.server_accept()
 51             print(self.client_addr)
 52             while True:
 53                 try:
 54                     res = self.conn.recv(self.max_recv_bytes)
 55                     if not res:continue
 56                     cmds = res.decode(self.coding).split()
 57                     if hasattr(self,cmds[0]):
 58                         func = getattr(self,cmds[0])
 59                         func(cmds)
 60                 except Exception:
 61                     break
 62             self.conn_close(self.conn)
 63 
 64     def get(self,cmds):
 65         """ 下载
 66         1.找到下载的文件
 67         2.发送 header_size
 68         3.发送 header_bytes file_size
 69         4.读文件 rb 发送 send(line)
 70         5.若文件不存在,发送0 client提示:文件不存在
 71         :param cmds: 下载的文件 eg:['get','a.txt']
 72         :return:
 73         """
 74         filename = cmds[1]
 75         file_path = os.path.join(self.down_filepath, filename)
 76         if os.path.isfile(file_path):
 77             header = {
 78                 'filename': filename,
 79                 'md5': 'xxxxxx',
 80                 'file_size': os.path.getsize(file_path)
 81             }
 82             header_bytes = pickle.dumps(header)
 83             self.conn.send(struct.pack('i', len(header_bytes)))
 84             self.conn.send(header_bytes)
 85             with open(file_path, 'rb') as f:
 86                 for line in f:
 87                     self.conn.send(line)
 88         else:
 89             self.conn.send(struct.pack('i', 0))
 90 
 91     def put(self,cmds):
 92         """ 上传
 93         1.接收4个bytes  得到文件的 header_size
 94         2.根据 header_size  得到 header_bytes  header_dic
 95         3.根据 header_dic  得到 file_size
 96         3.以写的形式 打开文件 f.write()
 97         :param cmds: 下载的文件 eg:['put','a.txt']
 98         :return:
 99         """
100         obj = self.conn.recv(4)
101         header_size = struct.unpack('i', obj)[0]
102         header_bytes = self.conn.recv(header_size)
103         header_dic = pickle.loads(header_bytes)
104         print(header_dic)
105         file_size = header_dic['file_size']
106         filename = header_dic['filename']
107 
108         with open('%s/%s' % (self.upload_filepath, filename), 'wb') as f:
109             recv_size = 0
110             while recv_size < file_size:
111                 res = self.conn.recv(self.max_recv_bytes)
112                 f.write(res)
113                 recv_size += len(res)
114 
115 
116 tcp_server = TCPServer(('127.0.0.1',8080))
117 tcp_server.run()
118 tcp_server.server_close()

 3.面向对象版本  客户端

  1 import socket
  2 import struct
  3 import pickle
  4 import os
  5 
  6 
  7 class FTPClient:
  8     address_family = socket.AF_INET
  9     socket_type = socket.SOCK_STREAM
 10     # 下载的文件存放路径
 11     down_filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'download')
 12     # 上传的文件存放路径
 13     upload_filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'share')
 14     coding = 'utf-8'
 15     max_recv_bytes = 8192
 16 
 17     def __init__(self, server_address, connect=True):
 18         self.server_address = server_address
 19         self.socket = socket.socket(self.address_family, self.socket_type)
 20         if connect:
 21             try:
 22                 self.client_connect()
 23             except Exception:
 24                 self.client_close()
 25 
 26     def client_connect(self):
 27         self.socket.connect(self.server_address)
 28 
 29     def client_close(self):
 30         self.socket.close()
 31 
 32     def run(self):
 33         while True:
 34             # get a.txt 下载   put a.txt 上传
 35             msg = input(">>>:").strip()
 36             if not msg: continue
 37             self.socket.send(msg.encode(self.coding))
 38             cmds = msg.split()
 39             if hasattr(self,cmds[0]):
 40                 func = getattr(self,cmds[0])
 41                 func(cmds)
 42 
 43     def get(self, cmds):
 44         """ 下载
 45         1.得到 header_size
 46         2.得到 header_types header_dic
 47         3.得到 file_size file_name
 48         4.以写的形式 打开文件
 49         :param cmds: 下载的内容 eg: cmds = ['get','a.txt']
 50         :return:
 51         """
 52         obj = self.socket.recv(4)
 53         header_size = struct.unpack('i', obj)[0]
 54         if header_size == 0:
 55             print('文件不存在')
 56         else:
 57             header_types = self.socket.recv(header_size)
 58             header_dic = pickle.loads(header_types)
 59             print(header_dic)
 60             file_size = header_dic['file_size']
 61             filename = header_dic['filename']
 62 
 63             with open('%s/%s' % (self.down_filepath, filename), 'wb') as f:
 64                 recv_size = 0
 65                 while recv_size < file_size:
 66                     res = self.socket.recv(self.max_recv_bytes)
 67                     f.write(res)
 68                     recv_size += len(res)
 69                     print('总大小:%s 已下载:%s' % (file_size, recv_size))
 70                 else:
 71                     print('下载成功!')
 72 
 73     def put(self, cmds):
 74         """ 上传
 75         1.查看上传的文件是否存在
 76         2.上传文件 header_size
 77         3.上传文件 header_bytes
 78         4.以读的形式 打开文件 send(line)
 79         :param cmds: 上传的内容 eg: cmds = ['put','a.txt']
 80         :return:
 81         """
 82         filename = cmds[1]
 83         file_path = os.path.join(self.upload_filepath, filename)
 84         if os.path.isfile(file_path):
 85             file_size = os.path.getsize(file_path)
 86             header = {
 87                 'filename': os.path.basename(filename),
 88                 'md5': 'xxxxxx',
 89                 'file_size': file_size
 90             }
 91             header_bytes = pickle.dumps(header)
 92             self.socket.send(struct.pack('i', len(header_bytes)))
 93             self.socket.send(header_bytes)
 94 
 95             with open(file_path, 'rb') as f:
 96                 send_bytes = b''
 97                 for line in f:
 98                     self.socket.send(line)
 99                     send_bytes += line
100                     print('总大小:%s 已上传:%s' % (file_size, len(send_bytes)))
101                 else:
102                     print('上传成功!')
103         else:
104             print('文件不存在')
105 
106 
107 ftp_client = FTPClient(('127.0.0.1',8080))
108 ftp_client.run()
109 ftp_client.client_close()
原文地址:https://www.cnblogs.com/alice-bj/p/8615348.html