• 网络编程(九)


    threading并发服务器


    相比多进程服务器的优缺点:
    缺点: 1. 需要用到同步互斥
    2. 可能受到GIL的影响,但是网络IO线程并发还是可以的
    优点: 资源消耗比较少


    使用模块 : threading socket

    步骤
    1. 创建套接字 绑定 监听
    2. 接收客户端连接请求 创建新的线程
    3. 主线程继续接收下一个客户端连接请求,分支线程处理客户端事件
    4. 处理事件结束,退出线程,关闭套接字


    基于并发的HttpServer

    1.使用并发方案,有助于建立长连接
    2.用线程完成并发消耗更小资源
    3.将服务器功能封装为类
    4.静态网页放在一个专门的文件夹中管理
    5.使用不同的模块处理客户端请求,这些放在一个文件夹中

    技术实现 :
    并发 : 多线程
    server 类的设计 :
    初始化 : 将socket返回值变为属性 并且增加一系列其他属性

    服务器启动方法 : 接受客户端连接请求,创建新的线程

    客户端处理函数 : handleRrequest

    cookie:
    sys.path : 是一个列表,可以添加路径。该列表中的路径,对python下的所有环境可见
    __import__() : 参数为一个目录, 等同于import 导入


    使用集成模块完成网络并发

    python3 ---》 socketserver 模块

    进程tcp并发 'ForkingMixIn','TCPServer','StreamRequestHandler'

    进程udp并发
    'ForkingMixIn' 'UDPServer','DatagramRequestHandler',

    线程tcp并发
    'ThreadingMixIn' 'TCPServer','StreamRequestHandler'

    线程udp并发
    'ThreadingMixIn', 'UDPServer','DatagramRequestHandler',

    'ForkingTCPServer',
    'ForkingUDPServer',
    'ThreadingTCPServer',
    'ThreadingUDPServer',


    **********************************************************************************
    这是一个http服务器
    '''
    1.实现了多线程并发
    2.讲server的创建部分封装为类
    3.后端可以处理不同的请求 
    '''
    from socket import *
    from threading import Thread
    import sys

    ADDR = ('0.0.0.0',8000)
    static_root = './static'
    handler_root = './handler'

    #httpserver 类
    class HTTPServer(object):
    def __init__(self,addr):
    self.sockfd = socket()
    self.sockfd.setsockopt
    (SOL_SOCKET,SO_REUSEADDR,1)
    self.sockfd.bind(addr)
    self.sockfd.listen(5)
    self.serveName = '127.0.0.1'
    self.servePort = 8000

    #服务器启动函数 : 接受客户端请求,创建新的线程
    def serveForever(self):
    while True:
    self.connfd,self.clientAddr =
    self.sockfd.accept()
    clientThread = Thread
    (target = self.handleRequest)
    clientThread.start()

    def setApp(self,application):
    self.application = application

    def handleRequest(self):
    #接收request请求
    self.recvData = self.connfd.recv(2048)
    requestHeaders = self.recvData.splitlines()
    for line in requestHeaders:
    print(line)

    #获取到从浏览器输入的具体请求
    getRequest =
    str(requestHeaders[0]).split(' ')[1]

    if getRequest[-3:] != '.py':
    if getRequest == '/':
    getFilename = static_root + "/index.html"
    else:
    getFilename = static_root + getRequest

    try:
    f = open(getFilename)
    except:
    responseHeaders = "HTTP/1.1 404 not found "
    responseHeaders += " "
    responseBody = "====sorry,file not find====="
    else:
    responseHeaders = "HTTP/1.1 200 OK "
    responseHeaders += " "
    responseBody = f.read()
    finally:
    response = responseHeaders + responseBody
    self.connfd.send(response.encode())
    else:
    #需要的环境变量
    env = {}
    bodyContent = self.application
    (env,self.startResponse)

    response = "HTTP/1.1 {} ".format(self.header_set[0])
    for header in self.header_set[1:]:
    response += "{0}:{1} ".format(*header)
    response += ' '
    response += bodyContent
    self.connfd.send(response.encode())

    self.connfd.close()

    def startResponse(self,status,response_headers):
    serverHeaders = [
    ('Date','2018-5-21'),
    ('Server',"HTTPServer 1.0"),
    ]
    self.header_set =
    [status,response_headers + serverHeaders]


    #控制服务器启动
    def main():
    # 启动时直接告知使用哪个模块哪个函数处理请求
    # python3 HttpServer.py module app
    if len(sys.argv) < 3:
    sys.exit("请选择一个模块和应用")
    #将handler文件夹加入搜索路径
    sys.path.insert(0,handler_root)
    #导入module模块
    m = __import__(sys.argv[1])
    #获取module 下的app 付给一个变量
    application = getattr(m,sys.argv[2])

    httpd = HTTPServer(ADDR)
    httpd.setApp(application)
    print("Serving HTTP on port 8000")
    httpd.serveForever()

    if __name__ == "__main__":
    main()


    ****************************************************************************
    #多进程tcp 

    from socketserver import *

    #创建服务器类
    # class Server(ForkingTCPServer)
    class Server(ForkingMixIn,TCPServer):
    pass

    #处理具体请求
    class Handler(StreamRequestHandler):
    def handle(self):
    #self.request 相当于 accept创建的新的套接字
    addr = self.request.getpeername()
    print("Connect from",addr)
    while True:
    data = self.request.recv(1024).decode()
    if not data:
    break
    self.request.send(b"receive your message")

    server = Server(('0.0.0.0',9999),Handler)
    server.serve_forever()

    ************************************************************************
    #!/usr/bin/python

    import socket,os,sys,traceback
    from threading import *

    host = '192.168.1.211'
    port = 9999

    def handler(clientsock):
    print ('New child')
    print('Got connection from',clientsock.getpeername())
    while True:
    data = clientsock.recv(1024).decode()
    if not len(data):
    break
    clientsock.send('receive your message'.encode())

    clientsock.close()

    s = socket.socket()
    s.bind((host,port))
    s.listen(5)

    while True:
    try:
    clientsock,clientaddr = s.accept()
    except KeyboardInterrupt:
    raise
    except:
    traceback.print_exc()
    continue

    t = Thread(target = handler,args = (clientsock,))
    t.setDaemon(1)
    t.start()

    s.close()

    ******************************************************************************
    from socket import *
    import os
    import sys
    import signal
    import time

    FILE_PATH = "/home/tarena/"

    class FtpServer(object):
    def __init__(self,connfd):
    self.connfd = connfd

    def do_list(self):
    filelist = os.listdir(FILE_PATH)
    #服务器确认请求是否可以执行
    if filelist == None:
    self.connfd.send(b"FALL")
    self.connfd.send(b'OK')
    time.sleep(0.1)
    for filename in filelist:
    if filename[0] != '.' and os.path.isfile(FILE_PATH + filename):
    self.connfd.send(filename.encode())
    time.sleep(0.1)
    self.connfd.send(b"##")
    print('文件列表发送完毕')
    return

    def do_get(self,filename):
    try:
    fd = open(FILE_PATH+filename,'rb')
    except:
    self.connfd.send(b"FALL")
    self.connfd.send(b'OK')
    time.sleep(0.1)
    for line in fd:
    self.connfd.send(line)
    fd.close()
    time.sleep(0.1)
    self.connfd.send(b'##')
    print("文件发送成功")
    return

    def do_put(self,filename):
    try:
    fd = open(FILE_PATH+filename,'w')
    except:
    self.connfd.send(b"FALL")
    self.connfd.send(b'OK')
    while True:
    data = self.connfd.recv(1024).decode()
    if data == '##':
    break
    fd.write(data)
    fd.close()
    print("接收文件完毕")
    return

    def main():
    if len(sys.argv) != 3:
    print("argv is error")
    sys.exit(1)
    HOST = sys.argv[1]
    PORT = int(sys.argv[2])
    ADDR = (HOST,PORT)
    BUFFERSIZE = 1024

    sockfd = socket()
    sockfd.bind(ADDR)
    sockfd.listen(5)
    signal.signal(signal.SIGCHLD,signal.SIG_IGN)
    while True:
    try:
    connfd,addr = sockfd.accept()
    except KeyboardInterrupt:
    sockfd.close()
    sys.exit(0)
    except Exception:
    continue
    print("客户端登录:",addr)
    pid = os.fork()
    if pid < 0:
    print("创建子进程失败")
    continue
    elif pid == 0:
    sockfd.close()
    ftp = FtpServer(connfd)
    #接收客户端请求
    while True:
    data = connfd.recv(BUFFERSIZE).decode()
    if data[0] == 'L':
    ftp.do_list()
    elif data[0] == 'G':
    filename = data.split(' ')[-1]
    ftp.do_get(filename)
    elif data[0] == "P":
    filename = data.split(' ')[-1]
    ftp.do_put(filename)
    elif data[0] == "Q":
    print("客户端退出")
    sys.exit(0)

    else:
    connfd.close()
    continue


    if __name__ == "__main__":
    main()

    ***********************************************************************
    from socket import *
    import sys
    import time

    class FtpClient(object):
    def __init__(self,sockfd):
    self.sockfd = sockfd

    def do_list(self):
    self.sockfd.send(b"L") #发送请求类型
    #接收服务器确认 OK or FALL
    data = self.sockfd.recv(1024).decode()
    if data == 'OK':
    while True:
    data = self.sockfd.recv(1024).decode()
    if data == '##':
    break
    print(data)
    print("文件列表展示完毕")
    return
    else:
    print("文件列表请求失败")
    return

    def do_get(self,filename):
    self.sockfd.send(("G " + filename).encode())
    #接收服务器确认 OK or FALL
    data = self.sockfd.recv(1024).decode()
    if data == 'OK':
    fd = open(filename,'w')
    while True:
    data = self.sockfd.recv(1024).decode()
    if data == '##':
    break
    fd.write(data)
    fd.close()
    print('%s 下载完成'%filename)
    return
    else:
    print("下载文件失败")
    return

    def do_put(self,filename):
    try:
    fd = open(filename,'rb')
    except:
    print("上传的文件不存在")
    return
    self.sockfd.send(("P " + filename).encode())
    #接收服务器确认 OK or FALL
    data = self.sockfd.recv(1024).decode()
    if data == 'OK':
    for line in fd:
    self.sockfd.send(line)
    fd.close()
    time.sleep(0.1)
    self.sockfd.send(b"##")
    print("上传文件 %s 完成"%filename)
    return
    else:
    print("上传文件失败")
    return

    def do_quit(self):
    self.sockfd.send(b"Q")

    def main():
    if len(sys.argv) != 3:
    print("argv is error")
    sys.exit(1)
    HOST = sys.argv[1]
    PORT = int(sys.argv[2])
    ADDR = (HOST,PORT)
    BUFFERSIZE = 1024
    sockfd = socket()
    sockfd.connect(ADDR)

    ftp = FtpClient(sockfd) #生产事件对象

    while True:
    print("********命令选项**********")
    print("******** list************")
    print("******** get file********")
    print("******** put file********")
    print("******** quit************")
    data = input("输入命令>>")

    if data[:4] == 'list':
    ftp.do_list()
    elif data[:3] == 'get':
    filename = data.split(' ')[-1]
    ftp.do_get(filename)
    elif data[:3] == 'put':
    filename = data.split(' ')[-1]
    ftp.do_put(filename)
    elif data[:4] == 'quit':
    ftp.do_quit()
    sockfd.close()
    sys.exit(0)
    else:
    print("请输出正确命令!!!")
    continue


    if __name__ == "__main__":
    main()


    ***********************************************************************
    import time
    #处理特定请求的模块
    def app(environ,start_response):
    status = '200 OK'
    response_headers =
    [('Content-Type','text/plain;charset=UTF-8')]

    start_response(status,response_headers)

    return " ====简单的app程序=== %s"%time.ctime()
    ***********************************************************************
  • 相关阅读:
    L309 单音节词读音规则(一)-辅音字母发音规则
    L308 New brain cells made throughout life
    L306 词汇题
    L305 发邮件15分钟
    L304 What Is Death?
    2019.3.22 Week 11 : ZigBee power test and field test
    L302 如何避免秃头
    2019.3.22 Week 12 : ZigBee and T/H chamber test
    L300 3月英语课下
    Pycharm使用方法之调整代码字体大小
  • 原文地址:https://www.cnblogs.com/wcin/p/9119238.html
Copyright © 2020-2023  润新知