zoukankan      html  css  js  c++  java
  • socketserver(并发)

     一.文件(图片)上传的简单的代码

      服务端

    import socket
    import json
    sock = socket.socket()
    sock.bind(("192.168.13.166",8899))
    sock.listen(5)
    while True:
        print("server is working...")
        conn,addr = sock.accept()
        while True:
            data = conn.recv(1024).decode("utf-8")
            file_info = json.loads(data)
            print("file_info",file_info)
            action = file_info.get("action")
            filename = file_info.get("filename")
            filesize = file_info.get("filesize")
            conn.send(b"200")
            with open("put/"+filename,"wb") as f:
                recv_data_length = 0
                while recv_data_length<filesize:
                    data = conn.recv(1024)
                    recv_data_length+=len(data)
                    f.write(data)
                    print("文件总大小: %s,已成功接受%s" %(filesize,recv_data_length ))
            print("接受成功!")

      客户端

    import socket
    import json
    import os
    sock = socket.socket()
    sock.connect(("192.168.13.166",8899))
    while True:
        cmd = input("请输入命令:")
        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")
        sock.send(file_info_json)
        code = sock.recv(1024).decode("utf-8")
        if code =="200":
            with open(filename,"rb") as f:
                for line in f:
                    sock.send(line)
        else:
            print("服务异常")

      文件上传

    import struct
    import socket
    import json
    import hashlib
    
    sock=socket.socket()
    sock.bind(('127.0.0.1',8800))
    sock.listen(5)
    while 1:
        print("server is working....")
        conn,addr= sock.accept()
        while 1:
            # 接收json的打包长度
            file_info_length_pack=conn.recv(4)
            file_info_length=struct.unpack("i",file_info_length_pack)[0]
            # 接收json字符串
            file_info_json=conn.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=conn.recv(1024)
                    recv_data_length+=len(data)
                    f.write(data)
                    # MD5摘要
                    md5.update(data)
                    print("文件总大小:%s,已成功接收%s"%(filesize,recv_data_length))
            print("接收成功!")
            conn.send(b"OK")
            print(md5.hexdigest())
            md5_val=md5.hexdigest()
            client_md5=conn.recv(1024).decode("utf8")
            if md5_val==client_md5:
                 conn.send(b"203")
            else:
                 conn.send(b"204")
    服务端
    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("文件上传失败!")
    客户端

    二.socketserver(并发)

    Python提供了两个基本的socket模块。

    一个是socket,它提供了标准的BSD Socket API;另一个是socketServer,它提供了服务器中心类,可以简化网络服务器的开发,其实就是对socket()的再封装。

    1.前言:

      虽说用Python编写简单的网络程序很方便,但复杂一点的网络程序还是用现成的框架比较好。这样就可以专心事务逻辑,而不是套接字的各种细节。SocketServer模块简化了编写网络服务程序的任务。同时SocketServer模块也是Python标准库中很多服务器框架的基础。

    2.网络类:

    SocketServer提供了4个基本的服务类:

    TCPServer针对TCP套接字流

    UDPServer针对UDP数据报套接字

    UnixStreamServer和UnixDatagramServer针对UNIX域套接字,不常用。

    3.请求处理类:

      要实现一项服务,还必须派生一个handler class请求处理类,并重写父类的handle()方法。handle方法就是用来专门是处理请求的。该模块是通过服务类和请求处理类组合来处理请求的。

      SocketServer模块提供的请求处理类有BaseRequestHandler,以及它的派生类StreamRequestHandler和DatagramRequestHandler。从名字看出可以一个处理流式套接字,一个处理数据报套接字。

    4.总结用SocketServer创建一个服务的步骤:

      1). 创建一个request handler class(请求处理类),并且这个类要继承BaseRequestHandler class,而且还要重写父类里面的handle()方法,跟客户端所有的交互都是在handle()里面完成的。

      2). 实例化一个server class对象(TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer 四选一),并将服务的地址和之前创建的request handler class(请求处理类)传递给实例化后的server class对象。

      3). 调用server class对象的handle_request() (只处理一个请求)或 serve_forever()(处理多个请求)方法来开始处理请求。

    5.

    ----socketserver

      虽说用Python编写简单的网络程序很方便,但复杂一点的网络程序还是用现成的框架比较 好。这样就可以专心事务逻辑,而不是套接字的各种细节。SocketServer模块简化了编写网络服务程序的任务。同时SocketServer模块也 是Python标准库中很多服务器框架的基础。

    socketserver在python2中为SocketServer,在python3种取消了首字母大写,改名为socketserver。

    socketserver中包含了两种类,一种为服务类(server class),一种为请求处理类(request handle class)。前者提供了许多方法:像绑定,监听,运行…… (也就是建立连接的过程) 后者则专注于如何处理用户所发送的数据(也就是事务逻辑)。

      一般情况下,所有的服务,都是先建立连接,也就是建立一个服务类的实例,然后开始处理用户请求,也就是建立一个请求处理类的实例。

    一个基于SocketServer的服务器示例:
     
     
    from SocketServer import TCPServer,StreamRequestHandler
     
    #定义请求处理类
     
    class Handler(StreamRequestHandler):
     
    def handle(self):
     
    addr = self.request.getpeername()
     
    print 'Got connection from ',addr
     
    self.wfile.write('Thank you for connecting')
     
    server = TCPServer(('',1234), handler)#实例化服务类对象
     
    server.server_forever()#开启服务
     

    6.实现异步,支持多连接

      前面介绍服务类时提到过,四个基本的服务类默认是同步模型的。要想支持异步可以利用多继承从ForkingMixIn 或ThreadingMixInmix-in classes和一个基本的服务类继承来定义一个支持异步的服务类。比如:

    class Server(ThreadingMixIn, TCPServer): pass

    ForkingMixIn 要考虑进程间的通信。ThreadingMixIn要考虑线程访问同一变量时的同步和互斥。

      SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进 程” 专门负责处理当前客户端的所有请求。

    启动服务端程序

      执行 TCPServer.init 方法,创建服务端Socket对象并绑定 IP 和 端口

      执行 BaseServer.init 方法,将自定义的继承自SocketServer.BaseRequestHandler 的类 - MyRequestHandle赋值给 self.RequestHandlerClass

      执行 BaseServer.server_forever 方法,While 循环一直监听是否有客户端请求到达 ... 当客户端连接到达服务器

      执行 ThreadingMixIn.process_request 方法,创建一个 “线程” 用来处理请求

      执行 ThreadingMixIn.process_request_thread 方法

      执行 BaseServer.finish_request 方法,执行 self.RequestHandlerClass() 即:执行  自定义 MyRequestHandler 的构造方法(自动调用基类BaseRequestHandler的构造方法,在该构造方法中又会调用  MyRequestHandler的handle方法)

    import socketserver
    class Myserver(socketserver.BaseRequestHandler):
        def handle(self):
            while 1:
                try:
                    print("等待信息")
                    data = self.request.recv(1024)
                    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()
    server=socketserver.ThreadingTCPServer(("127.0.0.1",8899),Myserver)
    server.serve_forever()
    服务端
    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'))
    客户端
  • 相关阅读:
    Android的各版本间的区别总结
    深入浅出Android开发之Surface介绍
    android中完全退出当前应用程序的四种方法
    android离线地图源码
    坐标系
    mysql安装
    linux磁盘空间清理
    HttpClient教程
    TIME_WAIT过多
    c3p0配置详解
  • 原文地址:https://www.cnblogs.com/chenxi67/p/9593036.html
Copyright © 2011-2022 走看看