python之路 - day29 socketserver模块,实现多线程的 server-client

socketserver模块

  使用socketserver模块,在server端,可同时接受多个client连接,并通讯

1.示例一:

  基于socketserver模块的框架、基本使用方法

服务端 程序示例:

import socketserver #模块

# 第一步: 自定义一个类,该类继承类:socketserver.BaseRequestHandler
class Myserver(socketserver.BaseRequestHandler):
    def handle(self): # 在类里 定义一个 handle(self)函数,函数名固定,不可更改
        '''
        函数体里,编写server端 的业务逻辑代码。当有多个client连接上时,将开启多个线程,分别执行handle函数
        :return:
        '''
        while 1:
            # 针对window系统
            try:
                print("等待信息")
                data = self.request.recv(1024)  # 阻塞
                # 针对linux
                if len(data) == 0:
                    break
                if data == b'exit':
                    break
                response = data + b'SB'
                self.request.send(response)
            except Exception as e:
                break

        self.request.close()

# 第二步: 实例化一个对象 ThreadingTCPServer
# 该步相当于-------- 1:创建socket对象 2:self.socket.bind()  3:self.socket.listen(5)
server=socketserver.ThreadingTCPServer(("127.0.0.1",8899),Myserver) # 第一个参数:封装了IP和Port的元祖 第二个参数: 自定义的类(该类继承类:socketserver.BaseRequestHandler)

# 第三步: 调用ThreadingTCPServer对象的.server_forever()     此步的动作,相当于 self.socket.accept()
server.serve_forever()
server

客户端 程序:

import socket

sk = socket.socket()

sk.connect(('127.0.0.1',8899))

while 1:
    name = input(">>>>:")
    sk.send(name.encode('utf-8')) # 字节

    response = sk.recv(1024) # 字节
    print(response.decode('utf-8'))
client

 

拓展: socketserver有以下TCP\UDP 类

  • socketserver.ThreadingTCPServer
  • socketserver.ThreadingUDPServer
  • socketserver.ForkingTCPServer
  • socketserver.ForkingUDPServer  

 

2.示例二:

  使用socketserver模块 实现功能: 服务端多线程的接收多个客户端上传文件

服务端 程序:

import socketserver

class myServer(socketserver.BaseRequestHandler):
    def handle(self):
        import struct
        import socket
        import json
        import hashlib
        print(self.client_address," 上线了!")
        while 1:
            # 接收json的打包长度
            file_info_length_pack = self.request.recv(4)  #接受数据时,使用 self.request.recv(),等同于之前我们使用的conn.recv()
            file_info_length = struct.unpack("i", file_info_length_pack)[0]

            # 接收json字符串
            file_info_json = self.request.recv(file_info_length).decode("utf8")
            file_info = json.loads(file_info_json)

            action = file_info.get("action")
            filename = file_info.get("filename")
            filesize = file_info.get("filesize")

            # 循环接收文件
            md5 = hashlib.md5()
            with open("put/" + filename, "wb") as f:
                recv_data_length = 0
                while recv_data_length < filesize:
                    data = self.request.recv(1024)
                    recv_data_length += len(data)
                    f.write(data)
                    # MD5摘要
                    md5.update(data)
                    msg = "文件名:{} 文件总大小:{},已成功接收{} 进度:{:.3f}%".format(filename,filesize, recv_data_length,
                                                               recv_data_length / filesize * 100)
                    print(msg)
            print(filename," 接收完成!")

            md5_val = md5.hexdigest()
            print(md5_val)

            if md5_val == file_info["md5value"]:  # 根据md5算法字符串,判断文件是否一致
                print(filename," 文件校验通过!")
                self.request.send(b"203")
            else:
                print(filename,"文件校验失败!")
                self.request.send(b"204")

#实例化一个 scoketserver.ThreadingTCPServer
server=socketserver.ThreadingTCPServer(('127.0.0.1',8800),myServer)

#接受 客户端连接
res=server.serve_forever()
服务端程序 (使用socketserver)

客户端 程序: (和使用socket模式的写法完全一样)

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,
        "md5value":""
    }
    #获取文件的md5字符串
    md5_1 = hashlib.md5()  # 示例化一个md5对象
    with open(filename,"rb") as f:
        for line in f:
            md5_1.update(line)
    file_info["md5value"]=md5_1.hexdigest() #将该字符串发送给server,用于验证接收的文件是否完全和发送时一样
    print(md5_1.hexdigest())

    file_info_json=json.dumps(file_info).encode("utf8") #将dict用jason处理后,得到jason格式的字符串,再编码成 bytes字节串
    ret=struct.pack("i",len(file_info_json)) #使用struct模块,将int转变为长度为4的bytes.

    # 发送 file_info_json的打包长度
    sock.send(ret)
    # 发送 file_info_json字节串
    sock.send(file_info_json)
    # 发送 文件数据

    with open(filename,"rb") as f:
        for line in f:
            sock.send(line)

    is_valid=sock.recv(1024).decode('utf8')
    if is_valid=="203":
        print(filename," 文件已成功上传!")
    else:
        print(filename,"文件上传失败!")
客户端程序 (使用socket模块)

  实现过程,结果如下:

 

 

 

 

 

 

 

 3.socketserver 类继承 示意图

 

 

 

 

 

 

 

posted @ 2019-11-21 11:51  风语9191  阅读(114)  评论(0)    收藏  举报