• 网络编程(九)


    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()
    ***********************************************************************
  • 相关阅读:
    平衡二叉树之RB树
    平衡二叉树之AVL树
    实现哈希表
    LeetCode Median of Two Sorted Arrays
    LeetCode Minimum Window Substring
    LeetCode Interleaving String
    LeetCode Regular Expression Matching
    PAT 1087 All Roads Lead to Rome
    PAT 1086 Tree Traversals Again
    LeetCode Longest Palindromic Substring
  • 原文地址:https://www.cnblogs.com/wcin/p/9119238.html
Copyright © 2020-2023  润新知