day29 文件的上传和下载 socketserver(并发)

文件上传的讲解:

1 import subprocess
2 
3 res=subprocess.Popen("dir",
4                      shell=True,
5                      stderr=subprocess.PIPE,
6                      stdout=subprocess.PIPE)
7 
8 
9 print(res.stdout.read().decode("gbk"))
server
 1 import socket
 2 import os
 3 import json   #序列化对象  : 把字典 列表变成字符串
 4 
 5 sock=socket.socket()
 6 sock.connect(("127.0.0.1",8800))
 7 
 8 
 9 while 1 :
10     cmd=input("请输入命令:") # put 111.jpg
11 
12     action,filename=cmd.strip().split(" ")
13     filesize=os.path.getsize(filename)
14 
15     file_info={
16         "action": action,
17         "filename": filename,
18         "filesize": filesize,
19     }
20     file_info_json=json.dumps(file_info).encode("utf8")
21     sock.send(file_info_json)
22 
23     # 确认服务端接收到了文件信息
24     code=sock.recv(1024).decode("utf8")
25     if code=="200":
26         # 发送文件数据
27         with open(filename,"rb") as f:
28             for line in f:
29                 sock.send(line)
30     else:
31         print("服务器异常!")
32 
33 
34 '''
35 
36 
37 '{.....}'   'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
38 
39 
40 
41 
42 '''
client
对上传的文件进行加密校验:
 1 import struct
 2 import socket
 3 import json
 4 import hashlib
 5 
 6 sock=socket.socket()
 7 sock.bind(('127.0.0.1',8800))
 8 sock.listen(5)
 9 
10 
11 
12 while 1:
13     print("server is working....")
14     conn,addr= sock.accept()
15     while 1:
16 
17         # 接收json的打包长度
18         file_info_length_pack=conn.recv(4)
19         file_info_length=struct.unpack("i",file_info_length_pack)[0]
20 
21         # 接收json字符串
22         file_info_json=conn.recv(file_info_length).decode("utf8")
23         file_info=json.loads(file_info_json)
24 
25         action=file_info.get("action")
26         filename=file_info.get("filename")
27         filesize=file_info.get("filesize")
28 
29         # 循环接收文件
30         md5=hashlib.md5()
31         with open("put/"+filename,"wb") as f:
32             recv_data_length=0
33             while recv_data_length<filesize:
34                 data=conn.recv(1024)
35                 recv_data_length+=len(data)
36                 f.write(data)
37                 # MD5摘要
38                 md5.update(data)
39                 print("文件总大小:%s,已成功接收%s"%(filesize,recv_data_length))
40 
41         print("接收成功!")
42         conn.send(b"OK")
43         print(md5.hexdigest())
44         md5_val=md5.hexdigest()
45         client_md5=conn.recv(1024).decode("utf8")
46         if md5_val==client_md5:
47              conn.send(b"203")
48         else:
49              conn.send(b"204")
server
import socket
import os
import json
import struct
import hashlib

sock=socket.socket()
sock.connect(("127.0.0.1",8800))


while 1 :
    cmd=input("请输入命令:") # put 111.jpg

    action,filename=cmd.strip().split(" ")
    filesize=os.path.getsize(filename)

    file_info={
        "action": action,
        "filename": filename,
        "filesize": filesize,
    }
    file_info_json=json.dumps(file_info).encode("utf8")

    ret=struct.pack("i",len(file_info_json))
    # 发送 file_info_json的打包长度
    sock.send(ret)
    # 发送 file_info_json字节串
    sock.send(file_info_json)
    # 发送 文件数据
    md5=hashlib.md5()
    with open(filename,"rb") as f:
        for line in f:
            sock.send(line)
            md5.update(line)

    data=sock.recv(1024)
    print(md5.hexdigest())
    md5_val=md5.hexdigest()
    sock.send(md5_val.encode("utf8"))
    is_valid=sock.recv(1024).decode('utf8')
    if is_valid=="203":
        print("文件完整!")
    else:
        print("文件上传失败!")
client

 

重要模块 socketserver

   内部使用IO多路复合,以及多线程、多进程,从而实现并发处理多个客户端请求的服务器

ThreadingTCPServer

ThreadingTCPServer实现的Soket服务器内部会为每个client创建一个 “线程”,该线程用来和客户端进行交互

1、ThreadingTCPServer基础

使用ThreadingTCPServer:

  • 创建一个继承自 SocketServer.BaseRequestHandler 的类
  • 类中必须定义一个名称为 handle 的方法
  • 启动ThreadingTCPServer
import SocketServer

class MyServer(SocketServer.BaseRequestHandler):

    def handle(self):
        # print self.request,self.client_address,self.server
        conn = self.request
        conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
        Flag = True
        while Flag:
            data = conn.recv(1024)
            if data == 'exit':
                Flag = False
            elif data == '0':
                conn.sendall('通过可能会被录音.balabala一大推')
            else:
                conn.sendall('请重新输入.')


if __name__ == '__main__':
    server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyServer)
    server.serve_forever()

SocketServer实现服务器
View Code
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket


ip_port = ('127.0.0.1',8009)
sk = socket.socket()
sk.connect(ip_port)
sk.settimeout(5)

while True:
    data = sk.recv(1024)
    print 'receive:',data
    inp = raw_input('please input:')
    sk.sendall(inp)
    if inp == 'exit':
        break

sk.close()

客户端
客户端

 SocketServer的ThreadingTCPServer之所以可以同时处理请求得益于 select 和 os.fork 两个东西,其实本质上就是在服务器端为每一个客户端创建一个进程,当前新创建的进程用来处理对应客户端的请求,所以,可以支持同时n个客户端链接(长连接)

原文地址:https://www.cnblogs.com/xiaobai686/p/11789871.html