• socket并发通信的几种方式


    1、socketserver

    socketserver模块是基于socket而来的模块,内部使用IO多路复用以及多线程和多进程,从而实现并发处理客服端请求的Socket服务器。

    即:每个客户端连接到服务器Socket服务端都会在服务端创建一个线程或者进程专门负责处理当前客户端的所有请求。

    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转人工服务.'.encode())
            Flag = True
            while Flag:
                data = conn.recv(1024)
                if data.decode() == 'exit':
                    Flag = False
                elif data.decode() == '0':
                    conn.sendall('通过可能会被录音.balabala一大推'.encode())
                else:
                    conn.sendall('请重新输入.'.encode())
    
    
    if __name__ == '__main__':
        server = socketserver.ThreadingTCPServer(('127.0.0.1',8009),MyServer)
        server.serve_forever()
    server
    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.decode())
        inp = input('please input:')
        sk.sendall(inp.encode())
        if inp == 'exit':
            break
    
    sk.close()
    client

    运行流程图

     从上图我们可以看出SocketServer主要被抽象为两个主要的类: BaseServer类,用于处理连接相关的网络操作 BaseRequestHandler类,用于实际处理数据相关的操作,SocketServer还提供了MixIn类:ThreadingMinxIn使用多进程多线程处理请求。

    内部调用流程为:

    • 启动服务端程序
    • 执行 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方法)

    2、使用多进程加select模拟socketServer的运行模式

    import socket
    import threading
    import select
    
    
    def process(request, client_address):
        print request,client_address
        conn = 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('请重新输入.')
    
    sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sk.bind(('127.0.0.1',8002))
    sk.listen(5)
    
    while True:
        r, w, e = select.select([sk,],[],[],1)
        print 'looping'
        if sk in r:
            print 'get request'
            request, client_address = sk.accept()
            t = threading.Thread(target=process, args=(request, client_address))
            t.daemon = False
            t.start()
    
    sk.close()
    sever
    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.decode())
        inp = input('please input:')
        sk.sendall(inp.encode())
        if inp == 'exit':
            break
    
    sk.close()
    client

     3、使用协程并发

    使用个gevent 实现server端的并发监控client的连接。

    from gevent import monkey;
    
    monkey.patch_all()
    from socket import *
    import gevent
    
    
    # 如果不想用money.patch_all()打补丁,可以用gevent自带的socket
    # from gevent import socket
    # s=socket.socket()
    def server(server_ip, port):
        s = socket(AF_INET, SOCK_STREAM)
        s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        s.bind((server_ip, port))
        s.listen(5)
        while True:
            conn, addr = s.accept()
            gevent.spawn(talk, conn, addr)
    
    
    def talk(conn, addr):
        try:
            while True:
                res = conn.recv(1024)
                print('client %s:%s msg: %s' % (addr[0], addr[1], res))
                conn.send(res.upper())
        except Exception as e:
            print(e)
        finally:
            conn.close()
    
    
    if __name__ == '__main__':
        server('127.0.0.1', 8000)
    server
    from multiprocessing import Process
    import socket
    import time
    
    def client(ip,port,i):
    
        s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        ip_port = (ip,port)
        s.connect(ip_port)
    
        while True:
            data = i
            s.sendall(data.encode('utf-8'))
            time.sleep(3)
            data_recv = s.recv(1024).decode('utf-8')
            print(data_recv)
    
    if __name__ == "__main__":
        count = 0
        for i in range(50):
            p = Process(target=client,args=('127.0.0.1',8000,str(i)))
            p.start()
            count += 1
    client
    人生苦短,我用cnblog
  • 相关阅读:
    浅析Java CompletionService
    经验总结13--EF配置
    消息摘要算法-HMAC算法
    03012_预处理对象executeQuery方法(实现数据库的查询)
    GO学习笔记:函数defer
    GO学习笔记:函数传值与传指针
    GO学习笔记:函数作为值、类型
    GO学习笔记:函数Panic和Recover
    GO学习笔记:import
    GO学习笔记:struct类型
  • 原文地址:https://www.cnblogs.com/wuzhibinsuib/p/13044604.html
Copyright © 2020-2023  润新知