python服务器

单进程阻塞版

#!/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服务器)