python入门第二十九天-socketserver

简单并发实例

服务端:

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
‘‘‘
Administrator
2018/8/3
‘‘‘
import socketserver

class MyServer(socketserver.BaseRequestHandler): #定义自己的类,继承固定的类 socketserver.BaseRequestHandler

    def handle(self):  #方法名 必须用handle  为了重新父类的方法
        print ("服务端启动...")
        while True:
            conn = self.request #相当于:conn, addr = s.accept()
            print (self.client_address)
            while True:
                client_data=conn.recv(1024)
                print (str(client_data,"utf8"))
                print ("waiting...")
                conn.sendall(client_data)
            conn.close()

if __name__ == ‘__main__‘:
    #调用socketserver 下的多线程TCPSERVer服务方法。需要两个参数,(ip port), 自己定义的类
    server = socketserver.ThreadingTCPServer((‘127.0.0.1‘,8091),MyServer)
    #调用serve_forever()方法。里面封装了
    server.serve_forever()

客户端:

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
‘‘‘
Administrator
2018/8/3
‘‘‘
#-----------------------------------------------------client.py
#-----------------------------------------------------
import socket

ip_port = (‘127.0.0.1‘,8091)
sk = socket.socket()
sk.connect(ip_port)
print ("客户端启动:")
while True:
    inp = input(‘>>>‘)
    sk.sendall(bytes(inp,"utf8"))
    if inp == ‘exit‘:
        break
    server_response=sk.recv(1024)
    print (str(server_response,"utf8"))
sk.close()

聊天并发实例

 1 #!/usr/bin/env python3
 2 #-*- coding:utf-8 -*-
 3 ‘‘‘
 4 Administrator
 5 2018/8/3
 6 ‘‘‘
 7 import socketserver
 8
 9 class MyServer(socketserver.BaseRequestHandler):
10
11     def handle(self):
12         print ("服务端启动...")
13         while True:
14             conn = self.request
15             print (self.client_address)
16             while True:
17
18                 client_data=conn.recv(1024)
19
20                 print (str(client_data,"utf8"))
21                 print ("waiting...")
22                 server_response=input(">>>")
23                 conn.sendall(bytes(server_response,"utf8"))
24                 # conn.sendall(client_data)
25
26             conn.close()
27             # print self.request,self.client_address,self.server
28
29
30 if __name__ == ‘__main__‘:
31     server = socketserver.ThreadingTCPServer((‘127.0.0.1‘,8098),MyServer)
32     server.serve_forever()

kehuduan:

 1 ##########################################
 2 import socket
 3
 4
 5 ip_port = (‘127.0.0.1‘,8098)
 6 sk = socket.socket()
 7 sk.connect(ip_port)
 8 print ("客户端启动:")
 9 while True:
10     inp = input(‘>>>‘)
11     sk.sendall(bytes(inp,"utf8"))
12     server_response=sk.recv(1024)
13     print (str(server_response,"utf8"))
14     if inp == ‘exit‘:
15         break
16 sk.close()



其它应用

命令传送1:

#------------------------------------------------server
#------------------------------------------------
import socket
import subprocess
ip_port = (‘127.0.0.1‘,8879)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(5)
print ("服务端启动...")
while True:
    conn,address = sk.accept()
    while True:
        try:

            client_data=conn.recv(1024)
        except Exception:
            break
        print (str(client_data,"utf8"))
        print ("waiting...")
        # server_response=input(">>>")
        # conn.sendall(bytes(server_response,"utf8"))
        cmd=str(client_data,"utf8").strip()
        cmd_call=subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE)
        cmd_result=cmd_call.stdout.read()
        if len(cmd_result)==0:
            cmd_result=b"no output!"
        conn.sendall(cmd_result)
        print(‘send data size‘,len(cmd_result))
        print(‘******************‘)
        print(‘******************‘)
        print(‘******************‘)

    conn.close()

#------------------------------------------------client
#------------------------------------------------
import socket
ip_port = (‘127.0.0.1‘,8879)
sk = socket.socket()
sk.connect(ip_port)
print ("客户端启动:")
while True:
    inp = input(‘cdm:>>>‘).strip( )
    if len(inp)==0:
        continue
    if inp=="q":
        break
    sk.sendall(bytes(inp,"utf8"))
    server_response=sk.recv(1024)
    print (str(server_response,"gbk"))
    print(‘receive data size‘,len(server_response))
    if inp == ‘exit‘:
        break
sk.close()

1

2

#试一试

netstat -an

conclusion:

sendall会把数据直接全部发送到客户端,客户端将所有的数据都放到缓冲区,每次recv多少字节取决于recv内的参数,理论不应该超过8k。

所以,并不能一次recv()无限大数据,所以这里我们应该通过循环去接收。


1

sk.recv(4096)  

命令传送2:解决大数据传送和粘包问题

import socketserver
import subprocess

class Myserver(socketserver.BaseRequestHandler):
    def handle(self):
        while True:
            conn=self.request
            conn.sendall(bytes("欢迎登录","utf8"))
            while True:
                client_bytes=conn.recv(1024)
                if not client_bytes:break
                client_str=str(client_bytes,"utf8")
                print(client_str)
                command=client_str

                result_str=subprocess.getoutput(command)
                result_bytes = bytes(result_str,encoding=‘utf8‘)
                info_str="info|%d"%len(result_bytes)
                conn.sendall(bytes(info_str,"utf8"))
                # conn.recv(1024)
                conn.sendall(result_bytes)
            conn.close()

if __name__=="__main__":
    server=socketserver.ThreadingTCPServer(("127.0.0.1",9998),Myserver)
    server.serve_forever()

#####################################client

import socket
ip_port=("127.0.0.1",9998)

sk=socket.socket()
sk.connect(ip_port)
print("客户端启动...")

print(str(sk.recv(1024),"utf8"))

while True:
    inp=input("please input:").strip()

    sk.sendall(bytes(inp,"utf8"))
    basic_info_bytes=sk.recv(1024)
    print(str(basic_info_bytes,"utf8"))
    # sk.send(bytes(‘ok‘,‘utf8‘))
    result_length=int(str(basic_info_bytes,"utf8").split("|")[1])

    print(result_length)
    has_received=0
    content_bytes=bytes()
    while has_received<result_length:
        fetch_bytes=sk.recv(1024)
        has_received+=len(fetch_bytes)
        content_bytes+=fetch_bytes
    cmd_result=str(content_bytes,"utf8")
    print(cmd_result)

sk.close()

import socket,os
ip_port=("127.0.0.1",8898)
sk=socket.socket()
sk.bind(ip_port)
sk.listen(5)
BASE_DIR=os.path.dirname(os.path.abspath(__file__))

while True:
    print("waiting connect")
    conn,addr=sk.accept()
    flag = True
    while flag:

            client_bytes=conn.recv(1024)
            client_str=str(client_bytes,"utf8")
            func,file_byte_size,filename=client_str.split("|",2)

            path=os.path.join(BASE_DIR,‘yuan‘,filename)
            has_received=0
            file_byte_size=int(file_byte_size)

            f=open(path,"wb")
            while has_received<file_byte_size:
                data=conn.recv(1024)
                f.write(data)
                has_received+=len(data)
            print("ending")
            f.close()

#----------------------------------------------client
#----------------------------------------------
import socket
import re,os,sys
ip_port=("127.0.0.1",8898)
sk=socket.socket()
sk.connect(ip_port)
BASE_DIR=os.path.dirname(os.path.abspath(__file__))
print("客户端启动....")

while True:
    inp=input("please input:")

    if inp.startswith("post"):
        method,local_path=inp.split("|",1)
        local_path=os.path.join(BASE_DIR,local_path)
        file_byte_size=os.stat(local_path).st_size
        file_name=os.path.basename(local_path)
        post_info="post|%s|%s"%(file_byte_size,file_name)
        sk.sendall(bytes(post_info,"utf8"))
        has_sent=0
        file_obj=open(local_path,"rb")
        while has_sent<file_byte_size:
            data=file_obj.read(1024)
            sk.sendall(data)
            has_sent+=len(data)
        file_obj.close()
        print("上传成功")

文件上传

注意:

1  纸条就是conn

2  一收一发

3   client_data=conn.recv(1024)

if  那边send一个空数据  这边recv为空,则recv继续阻塞,等待其他的数据。所以聊天的时候好好聊,别发空数据。




socketserver

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

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

Server类

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

Base class for server classes.


1

class BaseServer

This uses the Internet TCP protocol, which provides for continuous streams of data between the client and server.


1

class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)

This uses datagrams, which are discrete packets of information that may arrive out of order or be lost while in transit. The parameters are the same as for TCPServer


1

class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)

These more infrequently used classes are similar to the TCP and UDP classes, but use Unix domain sockets; they’re not available on non-Unix platforms. The parameters are the same as for TCPServer. 


1

2

class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)

class socketserver.UnixDatagramServer(server_address, RequestHandlerClass,bind_and_activate=True)<br><br>#---------

class UnixStreamServer(TCPServer):    address_family = socket.AF_UNIX

class UnixDatagramServer(UDPServer):    address_family = socket.AF_UNIX

BaseServer的源码:

class BaseServer:

    """Base class for server classes.

    Methods for the caller:

    - __init__(server_address, RequestHandlerClass)
    - serve_forever(poll_interval=0.5)
    - shutdown()
    - handle_request()  # if you do not use serve_forever()
    - fileno() -> int   # for select()

    Methods that may be overridden:

    - server_bind()
    - server_activate()
    - get_request() -> request, client_address
    - handle_timeout()
    - verify_request(request, client_address)
    - server_close()
    - process_request(request, client_address)
    - shutdown_request(request)
    - close_request(request)
    - service_actions()
    - handle_error()

    Methods for derived classes:

    - finish_request(request, client_address)

    Class variables that may be overridden by derived classes or
    instances:

    - timeout
    - address_family
    - socket_type
    - allow_reuse_address

    Instance variables:

    - RequestHandlerClass
    - socket

    """

    timeout = None

    def __init__(self, server_address, RequestHandlerClass):
        """Constructor.  May be extended, do not override."""
        self.server_address = server_address
        self.RequestHandlerClass = RequestHandlerClass
        self.__is_shut_down = threading.Event()
        self.__shutdown_request = False

    def server_activate(self):
        """Called by constructor to activate the server.

        May be overridden.

        """
        pass

    def serve_forever(self, poll_interval=0.5):
        """Handle one request at a time until shutdown.

        Polls for shutdown every poll_interval seconds. Ignores
        self.timeout. If you need to do periodic tasks, do them in
        another thread.
        """
        self.__is_shut_down.clear()
        try:
            while not self.__shutdown_request:
                # XXX: Consider using another file descriptor or
                # connecting to the socket to wake this up instead of
                # polling. Polling reduces our responsiveness to a
                # shutdown request and wastes cpu at all other times.
                r, w, e = _eintr_retry(select.select, [self], [], [],
                                       poll_interval)
                if self in r:
                    self._handle_request_noblock()

                self.service_actions()
        finally:
            self.__shutdown_request = False
            self.__is_shut_down.set()

    def shutdown(self):
        """Stops the serve_forever loop.

        Blocks until the loop has finished. This must be called while
        serve_forever() is running in another thread, or it will
        deadlock.
        """
        self.__shutdown_request = True
        self.__is_shut_down.wait()

    def service_actions(self):
        """Called by the serve_forever() loop.

        May be overridden by a subclass / Mixin to implement any code that
        needs to be run during the loop.
        """
        pass

    # The distinction between handling, getting, processing and
    # finishing a request is fairly arbitrary.  Remember:
    #
    # - handle_request() is the top-level call.  It calls
    #   select, get_request(), verify_request() and process_request()
    # - get_request() is different for stream or datagram sockets
    # - process_request() is the place that may fork a new process
    #   or create a new thread to finish the request
    # - finish_request() instantiates the request handler class;
    #   this constructor will handle the request all by itself

    def handle_request(self):
        """Handle one request, possibly blocking.

        Respects self.timeout.
        """
        # Support people who used socket.settimeout() to escape
        # handle_request before self.timeout was available.
        timeout = self.socket.gettimeout()
        if timeout is None:
            timeout = self.timeout
        elif self.timeout is not None:
            timeout = min(timeout, self.timeout)
        fd_sets = _eintr_retry(select.select, [self], [], [], timeout)
        if not fd_sets[0]:
            self.handle_timeout()
            return
        self._handle_request_noblock()

    def _handle_request_noblock(self):
        """Handle one request, without blocking.

        I assume that select.select has returned that the socket is
        readable before this function was called, so there should be
        no risk of blocking in get_request().
        """
        try:
            request, client_address = self.get_request()
        except OSError:
            return
        if self.verify_request(request, client_address):
            try:
                self.process_request(request, client_address)
            except:
                self.handle_error(request, client_address)
                self.shutdown_request(request)

    def handle_timeout(self):
        """Called if no new request arrives within self.timeout.

        Overridden by ForkingMixIn.
        """
        pass

    def verify_request(self, request, client_address):
        """Verify the request.  May be overridden.

        Return True if we should proceed with this request.

        """
        return True

    def process_request(self, request, client_address):
        """Call finish_request.

        Overridden by ForkingMixIn and ThreadingMixIn.

        """
        self.finish_request(request, client_address)
        self.shutdown_request(request)

    def server_close(self):
        """Called to clean-up the server.

        May be overridden.

        """
        pass

    def finish_request(self, request, client_address):
        """Finish one request by instantiating RequestHandlerClass."""
        self.RequestHandlerClass(request, client_address, self)

    def shutdown_request(self, request):
        """Called to shutdown and close an individual request."""
        self.close_request(request)

    def close_request(self, request):
        """Called to clean up an individual request."""
        pass

    def handle_error(self, request, client_address):
        """Handle an error gracefully.  May be overridden.

        The default is to print a traceback and continue.

        """
        print(‘-‘*40)
        print(‘Exception happened during processing of request from‘, end=‘ ‘)
        print(client_address)
        import traceback
        traceback.print_exc() # XXX But this goes to stderr!
        print(‘-‘*40)

There are five classes in an inheritance diagram, four of which represent synchronous servers of four types:

There are five classes in an inheritance diagram, four of which represent
synchronous servers of four types:

        +------------+
        | BaseServer |
        +------------+
              |
              v
        +-----------+        +------------------+
        | TCPServer |------->| UnixStreamServer |
        +-----------+        +------------------+
              |
              v
        +-----------+        +--------------------+
        | UDPServer |------->| UnixDatagramServer |
        +-----------+        +--------------------+

RequestHandler类

所有requestHandler都继承BaseRequestHandler基类。

class BaseRequestHandler:

    """Base class for request handler classes.

    This class is instantiated for each request to be handled.  The
    constructor sets the instance variables request, client_address
    and server, and then calls the handle() method.  To implement a
    specific service, all you need to do is to derive a class which
    defines a handle() method.

    The handle() method can find the request as self.request, the
    client address as self.client_address, and the server (in case it
    needs access to per-server information) as self.server.  Since a
    separate instance is created for each request, the handle() method
    can define arbitrary other instance variariables.

    """

    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()

    def setup(self):
        pass

    def handle(self):
        pass

    def finish(self):
        pass

源码

创建一个socketserver 至少分以下几步

  1. First, you must create a request handler class by subclassing the BaseRequestHandlerclass and overriding its handle() method; this method will process incoming requests.   
  2. Second, you must instantiate one of the server classes, passing it the server’s address and the request handler class.
  3. Then call the handle_request() orserve_forever() method of the server object to process one or many requests.
  4. Finally, call server_close() to close the socket.

    import socketserver
    
    class MyTCPHandler(socketserver.BaseRequestHandler):
        """
        The request handler class for our server.
    
        It is instantiated once per connection to the server, and must
        override the handle() method to implement communication to the
        client.
        """
    
        def handle(self):
            # self.request is the TCP socket connected to the client
            self.data = self.request.recv(1024).strip()
            print("{} wrote:".format(self.client_address[0]))
            print(self.data)
            # just send back the same data, but upper-cased
            self.request.sendall(self.data.upper())
    
    if __name__ == "__main__":
        HOST, PORT = "localhost", 9999
    
        # Create the server, binding to localhost on port 9999
        server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
    
        # Activate the server; this will keep running until you
        # interrupt the program with Ctrl-C
        server.serve_forever()

    让你的socketserver并发起来, 必须选择使用以下一个多并发的类


    1

    2

    3

    4

    5

    6

    7

    class socketserver.ForkingTCPServer

    class socketserver.ForkingUDPServer

    class socketserver.ThreadingTCPServer

    class socketserver.ThreadingUDPServer

    所以:

    server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
    #替换为
    server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)

    思考:

    1  tcp与udp的区别(三次握手后,建立连接,双向通道,一个收,一个发,tcp每次接到数据后都会有一个应答,有了应答,新的数据就会被覆盖掉)

    2  粘包  

原文地址:https://www.cnblogs.com/Mengchangxin/p/9413284.html

时间: 2024-10-08 05:58:51

python入门第二十九天-socketserver的相关文章

python入门第二十六天--网络通信

网络编程 自从互联网诞生以来,现在基本上所有的程序都是网络程序,很少有单机版的程序了. 计算机网络就是把各个计算机连接到一起,让网络中的计算机可以互相通信.网络编程就是如何在程序中实现两台计算机的通信. 举个例子,当你使用浏览器访问新浪网时,你的计算机就和新浪的某台服务器通过互联网连接起来了,然后,新浪的服务器把网页内容作为数据通过互联网传输到你的电脑上. 由于你的电脑上可能不止浏览器,还有QQ.Skype.Dropbox.邮件客户端等,不同的程序连接的别的计算机也会不同,所以,更确切地说,网络

python入门第二十四天----成员修饰符 类的特殊成员

1 #成员修饰符 修饰符可以规定内部的字段.属性.方法等 是共有的成员,私有的成员 2 class Foo: 3 def __init__(self,name,age): 4 self.name=name 5 self.age=age #可以在外部直接访问 6 7 obj=Foo('Jack',22) 8 print(obj.name) 9 print(obj.age) 共有字段 1 #成员修饰符 修饰符可以规定内部的字段.属性.方法等 是共有的成员,私有的成员 2 class Foo: 3 d

第二十九天 月出惊山鸟 —Spring的AOP_AspectJ @annotation

6月14日,阴转雨."四面垂杨十里荷,向云何处最花多, 画楼南畔夕阳和.天气乍凉人寂寞, 光阴须得酒消磨,且来花里听笙歌." 面向切面的框架AspectJ邂逅Spring,不仅造就一种简洁,更带来更多的选择空间. 上篇的切面与代理配置方式,麻烦且繁琐.好在Spring 与 AspectJ 进行了集成,从接口和配置的泥潭爬出,善莫大焉. 下面把上一篇Spring的AOP 的例子改写一下,达到同样的效果. 1-3步骤不变. 4.定义一个 Aspect 切面类BallHandler.java

第二十九天Python学习记录

带参数的命名函数,可以带一个或者多个参数 函数能够减少重复代码,使程序变的可扩展,使程序变得易维护 形参变量只有在被调用时才分配内存单元 实参可以是常量,变量,表达式,函数等,无论实参是何种类型的量,在进行函数调用时,他们都必须有确定的值,以便把这些值传递给形参 默认参数可以减少默认输入量,默认参数必须放在最后 关键参数,指定了参数名的就叫关键参数,关键参数必须放在位置参数之后 函数返回值,函数的外部代码想要获取函数的执行结果,就可以在函数里用return语句把结果返回,函数在执行过程中,只要遇

孤荷凌寒自学python第六十九天学习并实践beautifulsoup对象用法2

(完整学习过程屏幕记录视频地址在文末) 今天继续学习beautifulsoup对象的属性与方法等内容. 一.今天进一步了解到的BeautifulSoup模块中的一些用法小结: 1. Html标签对象.parent #返回直接上一级父级对象整体 2. Html标签对象.parents #parents返回从a对象的直接父级对象开始的各个逐个上升的父级直到<html></html>级为止的宗谱链,是一个生成器 3. Html标签对象.next_sibling #获取当前Html标签对象

python入门 第二天笔记

程序主文件标志if __name__=="__main__": 在程序执行python 1.py 时候 程序1.py __name__ 为 main调用其他文件是,__name__ 为程序自己名字等于__name__ 一切事物都是对象,对象是有类创建的 int 内部功能a = 95b = 10c = a.__divmod__(10) #分页用到,余数print (c)(9,5)a.__ge__() 大于等于返回True, >= 看类的方法 type()方法查看类型 dir()查看

python入门第二篇

python 有切片和迭片的两种操作 支持list 和tuple两种数据类型 list: 第一种操作[0:1] :以第0个索引开始,到索引1 结束, [:] 什么都没有写,则是从0开始. 第二种操作[::]  第二个分号,则是指的是采样的频率. 迭片的操作:所谓的迭代就是循环: #!/usr/bin/python d={'a':1,'b':2, 'c':3, 'd':5} print d for key in d: print key for value in d.itervalues(): p

走入计算机的第二十九天(继承与派生)

一 什么是继承 继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类 单继承:就相当于子类继承了一个父类.    多继承:就相当于子类继承了多个父类. python中类的继承分为:单继承和多继承 1 class ParentClass1: #定义父类 2 pass 3 4 class ParentClass2: #定义父类 5 pass 6 7 class SubClass1(ParentClass1): #单继承,基类是P

python入门第二天

1 .数据类型 数字(整形,长整形,浮点型,复数) 字符串 字节串:在介绍字符编码时介绍字节bytes类型 列表 元组 字典 集合 2.数字 整型与浮点型 #整型int 作用:年纪,等级,身份证号,qq号等整型数字相关 定义: age=10 #本质age=int(10) #浮点型float 作用:薪资,身高,体重,体质参数等浮点数相关 salary=3000.3 #本质salary=float(3000.3) #二进制,十进制,八进制,十六进制  3. 字符串 #作用:名字,性别,国籍,地址等描