zoukankan      html  css  js  c++  java
  • socket实现并发

    之前版本的服务端,在while true的大循环中,只要来一个连接直接就进入小循环当中了。

    在小链接中,只要不跳出来,服务端将一直处于这个小的通信循环当中。不能并发。

    soketserver版本:

    1、类Mysever就是用来实例化函数handle方法的。

    2、handle方法就是收发消息的过程(通信循环)。添加异常处理

    3、连接循环在if __name__ == '__main__'当中写入,只有右键运行整个程序的时候才能执行

    4、类TreadingTCPServer利用类MySever实例化得到一个对象s:将通信循环Mysever嵌套在 TreadingTCPServer 当中。

      实现多线程的服务端:实现并发,每来一个链接就可以通过mysever实例化建立一个收发消息handle函数来执行。

    soketserver模块介绍:

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

    socketserver模块可以简化网络服务器的编写,Python把网络服务抽象成两个主要的类,一个是Server类,用于处理连接相关的网络操作,另外一个则是RequestHandler类,用于处理数据相关的操作。并且提供两个MixIn 类,用于扩展 Server,实现多进程或多线程。

    socketsever中分为两大类:

    第一类:sever类:专门处理链接。最基本的有五个:

    它包含了种五种server类,BaseServer(不直接对外服务)。TCPServer使用TCP协议,UDPServer使用UDP协议,还有两个不常使用的,即UnixStreamServer和UnixDatagramServer,这两个类仅仅在unix环境下有用(AF_unix)。

    BaseSever ------> TCPServer(UnixStreamServer)-------> UDPServer(UnixDatagramServer),

    其中,TCPServer继承BaseSever,UDPServer继承TCPServer。

    UnixStreamServer(只能处理Unix平台上的TCP)继承TCPServer,UnixDatagramServer继承UDPServer。这俩一般也不会用到。

    #利用反射hasattr判断对象socket中是否含有AF_UNIX属性的地址家族
    
    if hasattr(socket,"AF_UNIX")
      __all__.extend(["UnixSteamServer","UnixDatagramServer","ThreadingUnixStreamServer","ThreadingUnixDatagramServer"]) #若有,则在原来的基础上添加有关unix的一系列类。
    #AF_Inet基于网络的地址家族

     跟并发有关的:

    进程:ForkingTCPServer继承ForkingMixIn和TCPServer,ForkingUDPServer继承ForkingMixIn和UDPServer

    线程:ThreadingTCPServer继承ThreadingMixIn和TCPServer,ThreadingUDPServer继承ThreadingMixIn和UDPServer

    第二类:request类:处理通信

    BaseRequestHandler()

    StreamRequestHandler()

    DatagramRequestHandler()

    #服务端socketserver的TCP版本
    import socketserver
    
    '''
        def __init__(self, request, client_address, server):
            self.request = request
            self.client_address = client_address
            self.server = server
            self.setup()
            try:
                self.handle()
            finally:
                self.finish()
    
    '''
    
    class MyServer(socketserver.BaseRequestHandler):
    
        def handle(self):           #必须写,因为一定会需要调用。handle用于控制通讯循环
            print('conn is: ',self.request)   #conn
            print('addr is: ',self.client_address) #addr
    
            while True:
                try:
                #收消息
                    data=self.request.recv(1024)
                    if not data:break
                    print('收到客户端的消息是',data,self.client_address)
    
                    #发消息
                    self.request.sendall(data.upper())
    
                except Exception as e:
                    print(e)
                    break
    
    if __name__ == '__main__':
        s=socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyServer) #多线程
        # ThreadingTCPServer中没有init,只能找他父类中的,他继承了ThreadingMixIn和TCPServer
        #在ThreadingMixIn中没有,找TCPServer中也没有,继续在TCPServer的父类BaseSever中找到__init__
    '''
        address_family = socket.AF_INET
        socket_type = socket.SOCK_STREAM
        request_queue_size = 5
        allow_reuse_address = False    #不允许重新使用地址
        
        def __init__(self,server_address,RequestHandlerClass,bind_and_activate=True):
            BaseServer.__init__(self,server_address,RequestHandlerClass)
            self.socket = socket.socket(self.address_family,self.socket_type)    #就是上几行中init定义之前写好的
            
            if bind_and_activate:      #绑定IP并激活
                try:
                    self.server_bind()   
                    self.server_active()    #active中self.socket.listen(self.request_queue_size)
                except:
                    self.server_close()
                    raise
    '''
        # s=socketserver.ForkingTCPServer(('127.0.0.1',8080),MyServer) #多进程
    #以下两行是init中写好的,init产生一个套接字对象,经历一个实例化过程
        # self.server_address = server_address
        # self.RequestHandlerClass = RequestHandlerClass
        print(s.server_address)           #('127.0.0.1',8080)
        print(s.RequestHandlerClass)    #<class '__main__.MyServer'>
        print(MyServer)                    #<class '__main__.MyServer'>
        print(s.socket) #<socket.socket fd=236, family=AddressFamily.AF_INET,type=SocketKind.SOCK_STREAM,proto=0>
        print(s.server_address)
        
        s.serve_forever()    #最终在TCPServer的父类BaseServer中找到,
        # forever中会while死循环一直执行来接收链接,一个request就一个链接conn,client_address接收的就是客户端地址
    #当中会执行self.process_request(request,client_address)   #在ThreadingMixIn中找到
    #完成链接循环,MyServer(request,client_address,self)   这才是最终得到的
    #同样Mysever中没有init,去找父类中的
    ##服务端socketserver的UDP版本,UDP当中用的不多
    import socketserver
    
    class MyServer(socketserver.BaseRequestHandler):
        def handle(self):
            print(self.request)
            print('收到客户端的消息是',self.request[0])
            self.request[1].sendto(self.request[0].upper(),self.client_address)
    
    
    if __name__ == '__main__':
        s=socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyServer) #多线程
        #在父类中UDPServer的父类TCPServer中的init,此时会先经历UDPServer中的一系列参数赋值
    '''
    class UDPServer(TCPServer):
        allow_reuse_address = False
        socket_type = socket.SOKET_DGRAM
        max_packet_size = 8192
        
    def __init__()    #产生UDP套接字,并进行绑定和激活
    # UDPServer自己定义的激活函数server_activate什么都不用做  
    '''
        s.serve_forever()

     认证客户端的链接合法性

    如果你想在分布式系统中实现一个简单的客户端链接认证功能,又不像SSL那么复杂,那么利用hmac+加盐的方式来实现

    #服务端
    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    from socket import *
    import hmac,os
    
    secret_key=b'linhaifeng bang bang bang'   #用于’加盐‘
    def conn_auth(conn):
        '''
        认证客户端链接
        :param conn:
        :return:
        '''
        print('开始验证新链接的合法性')
        msg=os.urandom(32)   #产生32个字节的随机数
        conn.sendall(msg)    #发送给客户端
        h=hmac.new(secret_key,msg)   #hash验证的模块,对产生的msg数据加盐
        digest=h.digest()        #得到数值
        respone=conn.recv(len(digest))   #接收客户端返回的hash值
        return hmac.compare_digest(respone,digest)   #判断服务端和客户端的hash是否相同
    
    def data_handler(conn,bufsize=1024):            #专门处理通信
        if not conn_auth(conn):
            print('该链接不合法,关闭')
            conn.close()
            return
        print('链接合法,开始通信')
        while True:
            data=conn.recv(bufsize)
            if not data:break
            conn.sendall(data.upper())
    
    def server_handler(ip_port,bufsize,backlog=5):   
        '''
        只处理链接
        :param ip_port:
        :return:
        '''
        tcp_socket_server=socket(AF_INET,SOCK_STREAM)
        tcp_socket_server.bind(ip_port)
        tcp_socket_server.listen(backlog)
        while True:
            conn,addr=tcp_socket_server.accept()
            print('新连接[%s:%s]' %(addr[0],addr[1]))
            data_handler(conn,bufsize)
    
    if __name__ == '__main__':
        ip_port=('127.0.0.1',9999)
        bufsize=1024
        server_handler(ip_port,bufsize)
    #客户端(合法)
    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    from socket import *
    import hmac,os
    
    secret_key=b'linhaifeng bang bang bang'
    def conn_auth(conn):
        '''
        验证客户端到服务器的链接
        :param conn:
        :return:
        '''
        msg=conn.recv(32)
        h=hmac.new(secret_key,msg)
        digest=h.digest()
        conn.sendall(digest)
    
    def client_handler(ip_port,bufsize=1024):
        tcp_socket_client=socket(AF_INET,SOCK_STREAM)
        tcp_socket_client.connect(ip_port)
    
        conn_auth(tcp_socket_client)
    
        while True:
            data=input('>>: ').strip()
            if not data:continue
            if data == 'quit':break
    
            tcp_socket_client.sendall(data.encode('utf-8'))
            respone=tcp_socket_client.recv(bufsize)
            print(respone.decode('utf-8'))
        tcp_socket_client.close()
    
    if __name__ == '__main__':
        ip_port=('127.0.0.1',9999)
        bufsize=1024
        client_handler(ip_port,bufsize)
    #不知道加密方式
    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    from socket import *
    
    def client_handler(ip_port,bufsize=1024):
        tcp_socket_client=socket(AF_INET,SOCK_STREAM)
        tcp_socket_client.connect(ip_port)
    
        while True:
            data=input('>>: ').strip()
            if not data:continue
            if data == 'quit':break
    
            tcp_socket_client.sendall(data.encode('utf-8'))
            respone=tcp_socket_client.recv(bufsize)
            print(respone.decode('utf-8'))
        tcp_socket_client.close()
    
    if __name__ == '__main__':
        ip_port=('127.0.0.1',9999)
        bufsize=1024
        client_handler(ip_port,bufsize)
    #知道认证方式,不知道加的什么盐
    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    from socket import *
    import hmac,os
    
    secret_key=b'linhaifeng bang bang bang'
    def conn_auth(conn):
        '''
        验证客户端到服务器的链接
        :param conn:
        :return:
        '''
        msg=conn.recv(32)
        h=hmac.new(secret_key,msg)
        digest=h.digest()
        conn.sendall(digest)
    
    def client_handler(ip_port,bufsize=1024):
        tcp_socket_client=socket(AF_INET,SOCK_STREAM)
        tcp_socket_client.connect(ip_port)
    
        conn_auth(tcp_socket_client)
    
        while True:
            data=input('>>: ').strip()
            if not data:continue
            if data == 'quit':break
    
            tcp_socket_client.sendall(data.encode('utf-8'))
            respone=tcp_socket_client.recv(bufsize)
            print(respone.decode('utf-8'))
        tcp_socket_client.close()
    
    if __name__ == '__main__':
        ip_port=('127.0.0.1',9999)
        bufsize=1024
        client_handler(ip_port,bufsize)
  • 相关阅读:
    软件工程-个人最终总结
    结对编程—电梯调度
    第三周(第三作业)感想
    周三第二个作业
    VS2013安装和单元测试
    对京东的评价
    简单的四则运算
    迷茫的软件工程
    vlan 和 子网
    ECLIPSE的jar包和文件的导入导出
  • 原文地址:https://www.cnblogs.com/Josie-chen/p/9001582.html
Copyright © 2011-2022 走看看