zoukankan      html  css  js  c++  java
  • SocketServer模块

    利用select实现伪并发的socket博文中我们说了:

    如果要实现一个server端可以和多个客户端进行通信可以使用

    1.多线程

    2.多进程

    3.select I/O多路复用

    在那篇博文中我们介绍了使用select模块实现单线程的伪并发的程序间的通信,那今天我们就来谈一谈如何使用多线程来实现并发.

    Pyhton本身就提供了一个基于多线程实现并发socket的模块---->SocketServer模块。那么今天我们就来探讨一下SocketSever模块.

     SocetServer模块实现并发的原理就是:每有一个客户端连接进来,就会起一个线程负责和这个客户端进行通信。

    使用SocketServer模块的时候必须在自定义的类中定义一个handle(方法名必须是handle,差一个字母都不行)方法,在handle方法中去定义具体的操作。

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import SocketServer
    
    class MyServer(SocketServer.BaseRequestHandler):
        def handle(self):
            conn = self.request #如果连接请求过来,获取client端对象
            conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.') #发送一个信息
            Flag = True #并把Flag设置为True
            while Flag:#当Flag为True的时候执行
                data = conn.recv(1024) #接收client端数据
                if data == 'exit': #判断如果data  == 'exit' 退出
                    Flag = False #并把Flag设置为Flase
                elif data == '0': #如果为 == ‘0’
                    conn.sendall('通过可能会被录音.balabala一大推') #发送数据
                else:#上面的都没匹配上,发送请重新输入
                    conn.sendall('请重新输入.')
    
    
    if __name__ == '__main__':
        server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyServer) #实例化对象,设置启动的IP/PORT并把自己定义的类写上作为SocketServer.ThreadingTCPServer的构造函数
        server.serve_forever() #调用对象中的启动方法
    server
    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    
    import socket
    
    client = socket.socket()
    client.connect(('127.0.0.1',8009))
    #client.settimeout(5)
    
    while True:
        client_input = raw_input('please input message:').strip()
        client.sendall(client_input)
        server_data = client.recv(1024)
        print server_data
    client

    server端的代码实现其实非常简单,但是问题来了:为什么非得让我们定义一个handle方法呢?

      ok,看源码。

    学会看源码非常重要!不能仅仅光会用!大赞~ 知道他的过程和实现~ 怎么学会看源码呢?多看然后画类图,如上图!!!

    在理解的时候可以把他们想象为,把所有需要用的方法,都抓到ThreadingTCPServer中

    内部调用流程为:

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

    精简源码:

    模拟Socekt Server的简化版本:

    import socket
    import threading
    import select
    
    
    def process(request, client_address): #模拟定义的handle()方法,这个方法内的代码是socket server与Client端交互代码
        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:  #这里一个while循环循环监控sk文件句柄
        r, w, e = select.select([sk,],[],[],1)
        print 'looping'
        if sk in r: #当sk文件句柄发生变化的时候说明是新的客户端连接过来了
            print 'get request'
            request, client_address = sk.accept()
            t = threading.Thread(target=process, args=(request, client_address)) #创建一个线程,并调用自己定义的process方法执行~然后样客户端与之交互
            t.daemon = False
            t.start()
    
    sk.close()
    精简版

    如精简代码可以看出,SocketServer的ThreadingTCPServer之所以可以同时处理请求得益于 select 和 Threading 两个东西,其实本质上就是在服务器端为每一个客户端创建一个线程,当前线程用来处理对应客户端的请求,所以,可以支持同时n个客户端链接(长连接)。

     参考资料:

    http://www.cnblogs.com/luotianshuai/p/5111587.html

  • 相关阅读:
    位置边框深度探索QT窗口系统几何篇2
    下载图片封装一个工具类,搞定图片批量下载
    svn判断通过svnkit,获取最新的revision以及判断某个revsion是否存在
    java路径Java开发中获得非Web项目的当前项目路径
    遍历文件Java中遍历出指定目录中的所有文件
    存储过程程序存储过程编程5
    工具设置Unity3D系列教程使用免费工具在Unity3D中开发2D游戏 第一节
    破解学习Asprise OCR v4.0 64位破解...仅供学习使用
    宽度拉伸9patch图的尺寸尽量为偶数
    nullnull用宏定义swap(x,y)
  • 原文地址:https://www.cnblogs.com/along1226/p/5646710.html
Copyright © 2011-2022 走看看