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 如果不能成功,说明服务端有防火 阿里云或其它云还一个大防火
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容

  • 必备的理论基础 1.操作系统作用: 隐藏丑陋复杂的硬件接口,提供良好的抽象接口。 管理调度进程,并将多个进程对硬件...
    drfung阅读 3,533评论 0 5
  • python服务器高并发编程 1.socket相关概念 注意:请别关注图从哪里来,我只是想把知识点讲清楚 进程与进...
    一手好厨艺的IT民工阅读 1,525评论 0 1
  • web服务器使用多进程、多线程的原因如果没有多进程和多线程,那么任务是单任务的,即在,为一个顾客服务的时候,不能同...
    Jalynn葸阅读 210评论 1 0
  • 最新心血来潮,想玩玩python于是自己花钱,租了一台阿里云服务器玩玩. 第一次搭建, 处于摸着石头过河阶段,踩了...
    股金杂谈阅读 2,528评论 11 32
  • “现在毕业了,学长会怎么跟四年前的你告别?” 他会心一笑,目光移向了湖面,然后,又把目光转向了我,仿佛,我就是他四...
    焚离阅读 497评论 0 0