美文网首页
python服务器

python服务器

作者: 程序员Darker | 来源:发表于2019-03-04 15:17 被阅读0次

    单进程阻塞版

    #!/usr/bin/env python
    # encoding: utf-8
    
    from socket import *
    
    def main():
        # 1.创建Socket对象
        tcp_server = socket()
        # 2不会出现端口被占用
        tcp_server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        # 2.绑定IP地址和端口
        tcp_server.bind(("", 9999))
        # 3.把主动模式变成被动模式,一旦改变,这个Socket对象只能接,不能拨号
        tcp_server.listen(5)
        # 4.等待客户端连接
        while True:
            new_socket, client_info = tcp_server.accept()
            print(f"有新的客户{client_info}来了")
            # 5.接收消息
            raw_data = new_socket.recv(1024)
            # 5.1判断消息
            if raw_data:
                print(f"收到来自{client_info}的消息:{raw_data.decode('utf-8')}")
            else:
                break
        # 6.关闭连接
        new_socket.close()
    
    
    if __name__ == '__main__':
        main()
    
    

    同时只能为一个人服务

    多进程阻塞版本

    #!/usr/bin/env python
    # encoding: utf-8
    
    from socket import *
    from multiprocessing import Process
    
    
    # 处理数据
    def rec_data(sock, client_info):
        while True:
            # 5.接收消息
            raw_data = sock.recv(1024)
            # 5.1判断消息
            if raw_data:
                print(f"收到来自{client_info}的消息:{raw_data.decode('utf-8')}")
            else:
                # 6.关闭连接
                sock.close()
                break
    
    
    def main():
        # 1.创建Socket对象
        tcp_server = socket()
        # 2不会出现端口被占用
        tcp_server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        # 2.绑定IP地址和端口
        tcp_server.bind(("", 7777))
        # 3.把主动模式变成被动模式,一旦改变,这个Socket对象只能接,不能拨号
        tcp_server.listen(5)
    
        # 4.等待客户端连接
        while True:
            new_socket, client_info = tcp_server.accept()
            print(f"有新的客户{client_info}来了")
            # 创建新的进程
            p = Process(target=rec_data, args=(new_socket, client_info))
            # 启动进程
            p.start()
            # 不能全使用JOIN
            # p.join()
            # rec_data(new_socket, client_info)
            # 关闭主进程中的new_socket
            new_socket.close()
    
    
    if __name__ == '__main__':
        main()
    
    
    

    代表作:Apache

    new_socket在主进程一定要关闭,因为子进程会复制一份父进程内存空间

    多线程阻塞版本

    #!/usr/bin/env python
    # encoding: utf-8
    
    from socket import *
    from threading import Thread
    
    
    # 处理数据
    def rec_data(sock, client_info):
        while True:
            # 5.接收消息
            raw_data = sock.recv(1024)
            # 5.1判断消息
            if raw_data:
                print(f"收到来自{client_info}的消息:{raw_data.decode('utf-8')}")
            else:
                # 6.关闭连接
                sock.close()
                break
    
    
    def main():
        # 1.创建Socket对象
        tcp_server = socket()
        # 2不会出现端口被占用
        tcp_server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        # 2.绑定IP地址和端口
        tcp_server.bind(("", 7788))
        # 3.把主动模式变成被动模式,一旦改变,这个Socket对象只能接,不能拨号
        tcp_server.listen(5)
    
        # 4.等待客户端连接
        while True:
            new_socket, client_info = tcp_server.accept()
            print(f"有新的客户{client_info}来了")
            # 创建新的进程
            t = Thread(target=rec_data, args=(new_socket, client_info))
            # 启动进程
            t.start()
            # 不能全使用JOIN
            # p.join()
            # rec_data(new_socket, client_info)
            # 在多线程中,共享内存空间,不能关闭主线程中的new_socket
            # new_socket.close()
    
    
    if __name__ == '__main__':
        main()
    
    

    代表作:IIS 微软在Window上一个Web服务器

    在主线中new_socket不能关闭,因为子线程和主线程共用内存空间

    单进程非阻塞版并发服务器

    #!/usr/bin/env python
    # encoding: utf-8
    
    from socket import *
    
    
    def main():
        # 1.创建Socket对象
        tcp_server = socket()
        # 设置socket属性为非阻塞
        tcp_server.setblocking(False)
        # 2不会出现端口被占用
        tcp_server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        # 2.绑定IP地址和端口
        tcp_server.bind(("", 9990))
        # 3.把主动模式变成被动模式,一旦改变,这个Socket对象只能接,不能拨号
        tcp_server.listen(5)
        # 定义一个列表
        socket_lists = []
        # 4.等待客户端连接
        while True:
            try:
                new_socket, client_info = tcp_server.accept()
                # 设置新对象为非阻塞
                new_socket.setblocking(False)
                # 把新对象放在列表中
                socket_lists.append((new_socket, client_info))
            except:
                pass
            else:
                print(f"新的连接{client_info}")
            for sock, client in socket_lists:
                # 5.接收消息
                try:
                    raw_data = sock.recv(1024)
                except:
                    pass
                else:
                    # 5.1判断消息
                    if raw_data:
                        print(f"收到来自{client}的消息:{raw_data.decode('utf-8')}")
                    else:
                        # 关闭
                        sock.close()
                        # 删除列表中的对象
                        socket_lists.remove((sock, client))
                        break
    
    if __name__ == '__main__':
        main()
    
    

    [图片上传失败...(image-18f1a0-1551683757215)]

    [图片上传失败...(image-de506c-1551683757215)]

    虽然能够实现并发处理,但是CPU会100%,一直死循环,现实中不会使用

    IO多路复用

    概念

    用单进程实现并发请求

    select版本

    #!/usr/bin/env python
    # encoding: utf-8
    
    
    from socket import *
    import select
    
    
    def main():
        # 1.创建Socket对象
        tcp_server = socket()
        # 2不会出现端口被占用
        tcp_server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        # 2.绑定IP地址和端口
        tcp_server.bind(("", 7755))
        # 3.把主动模式变成被动模式,一旦改变,这个Socket对象只能接,不能拨号
        tcp_server.listen(5)
        # 4.把主套接字加入到公共监控区
        socket_lists = [tcp_server]
        # 5.内核监听
        while True:
            # 5.1 如果socket_lists有响动,这一句就会解阻塞,并返回有响动的对象
            read_lists, _, _ = select.select(socket_lists, [], [])
            # 5.2 循环遍历
            for sock in read_lists:
                # 5.2.1判断这个对象就是主对象 前台小姐姐
                if sock is tcp_server:
                    new_socket, client_info = sock.accept()
                    # 把新加入监视区
                    socket_lists.append(new_socket)
                else:
                    # 接收消息
                    raw_data = sock.recv(1024)
                    # 判断消息
                    if raw_data:
                        print(f"收到消息:{raw_data.decode('utf-8')}")
                    else:
                        # 关闭连接
                        sock.close()
                        # 删除列表
                        socket_lists.remove(sock)
    
    
    if __name__ == '__main__':
        main()
    

    最大连接数限制:32位系统1024个连接 64位2048个连接

    轮询

    poll:什么也没有做,只是去掉最大的连接数,内存限制,数量大了,自动就暴了

    [图片上传失败...(image-3597ad-1551683757215)]

    epoll版本

    #!/usr/bin/env python
    # encoding: utf-8
    
    from socket import *
    import select
    
    
    def main():
        # 1.创建Socket对象
        tcp_server = socket()
        # 设置socket属性为非阻塞
        tcp_server.setblocking(True)
        # 2不会出现端口被占用
        tcp_server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        # 2.绑定IP地址和端口
        tcp_server.bind(("", 9999))
        # 3.把主动模式变成被动模式,一旦改变,这个Socket对象只能接,不能拨号
        tcp_server.listen(5)
        # 4. epool只能在LINUX上使用 创建一个epool对象
        epool = select.epoll()
    
        # 5.fd 文件描述符
        print(f"tcp_server的文件描述符:{tcp_server.fileno()}")
        # 5.加到监听区
        epool.register(tcp_server.fileno(), select.EPOLLIN)
    
        # 创建一个字典 用来存新的小姐姐
        new_socket_dicts = {}
        client_info_dicts = {}
        while True:
            print(f"当前new_socket_dicts:{new_socket_dicts}")
            # 6.1 监听中
            epool_lists = epool.poll()
            print(f"epool_lists:{epool_lists}")
            # 循环 epool_lists
            for fd, events in epool_lists:
                # 判断是不是主套接字
                if fd == tcp_server.fileno():
                    # 创建新的对象 小姐姐
                    new_socket, client_info = tcp_server.accept()
                    # 把新小姐姐丢到监控区
                    epool.register(new_socket.fileno(), select.EPOLLIN)
                    # 把新的小姐姐存到字典  new_socket_dicts = {"3":new_socket}
                    new_socket_dicts[new_socket.fileno()] = new_socket
                    client_info_dicts[new_socket.fileno()] = client_info
                else:
    
                    # 接收数据 fd = 3
                    raw_data = new_socket_dicts[fd].recv(1024)
                    if raw_data:
                        print(f"收到数据来自{client_info_dicts[fd]} 消息{raw_data.decode('utf-8')}")
                    else:
                        # 关闭连接
                        new_socket_dicts[fd].close()
                        # 注销
                        epool.unregister(fd)
                        break
    
    
    if __name__ == '__main__':
        main()
    
    

    文件描述符:一个Socket对象的编号

    专业名词

    1. IO阻塞:只要是IO操作,一定有缓存区,一定是读写操作,默认阻塞,我们去取东西,如果有东西就取出来,如果没有就一直在那里等着,等到有东西为止
    2. IO非阻塞:我去取东西,如果有东西就把东西取出来,如果没有,我掉头就走
    3. 轮询:一个一个去问,每一个人都要问到
    4. 事件通知机制:不再一个一个问,你们有事主动通知我,我再做处理

    网路不通解决

    1. ping: ping 172.16.13.236
    2. 在服务端运行:netstat -natu | grep "9999" 确定服务有没有启动
    3. 在客户端:telnet 172.16.13.236 9999 如果不能成功,说明服务端有防火 阿里云或其它云还一个大防火

    相关文章

      网友评论

          本文标题:python服务器

          本文链接:https://www.haomeiwen.com/subject/bldiuqtx.html