[Python] Mini server

一. Web静态服务器

显示固定的页面

复制代码
# -*- coding: utf-8 -*-
# Time    : 2019/2/10 18:22
# Author  : Mifen
# Email   : 2952277346@qq.com
# Software: PyCharm

import socket


def service_client(conn):
    '''接收客户端发送的数据'''
    request = conn.recv(1024)
    print(request)
    # 返回客户端请求的数据
    response = 'HTTP/1.1 200 OK\r\n'
    response += '\r\n'
    response += '你好雇佣兵'
    conn.send(response.encode('utf-8'))
    conn.close()


def main():
    ''' 实现主要的功能控制'''
    # 1.创建socket
    serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 设置当服务器先close 即服务器端4次挥手之后资源能够立即释放,这样就保证了,下次运行程序时 可以立即绑定8080端口
    serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    # 2.绑定端口
    serversocket.bind(('', 8080))
    # 3.监听
    serversocket.listen(128)
    while True:
        # 4.等待连接
        conn, addr = serversocket.accept()
        # 5.与客户端通信
        service_client(conn)


if __name__ == '__main__':
    main()
复制代码

显示需要的页面

复制代码
# -*- coding: utf-8 -*-
# Time    : 2019/2/10 19:52
# Author  : Mifen
# Email   : 2952277346@qq.com
# Software: PyCharm
import socket
import re


def handle_client(client_socket):
    "为一个客户端进行服务"
    recv_data = client_socket.recv(1024).decode('utf-8', errors="ignore")
    request_header_lines = recv_data.splitlines()
    for line in request_header_lines:
        print(line)

    http_request_line = request_header_lines[0]
    get_file_name = re.match("[^/]+(/[^ ]*)", http_request_line).group(1)
    print("file name is ===>%s" % get_file_name)  # for test

    # 如果没有指定访问哪个页面。例如index.html
    # GET / HTTP/1.1
    if get_file_name == "/":
        get_file_name = r'html/index.html'
    else:
        get_file_name = 'html' + get_file_name

    print("file name is ===2>%s" % get_file_name)  # for test

    try:
        f = open(get_file_name, "rb")
    except IOError:
        # 404表示没有这个页面
        response_headers = "HTTP/1.1 404 not found\r\n"
        response_headers += "\r\n"
        response_body = "404 not found"
    else:
        response_headers = "HTTP/1.1 200 OK\r\n"
        response_headers += "\r\n"
        response_body = f.read()
        f.close()
    finally:
        # 因为头信息在组织的时候,是按照字符串组织的,不能与以二进制打开文件读取的数据合并,因此分开发送
        # 先发送response的头信息
        client_socket.send(response_headers.encode('utf-8'))
        # 再发送body
        client_socket.send(response_body)
        client_socket.close()


def main():
    "作为程序的主控制入口"
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_socket.bind(("127.0.0.1", 8080))
    server_socket.listen(128)
    while True:
        client_socket, clien_cAddr = server_socket.accept()
        handle_client(client_socket)


# 这里配置服务器
DOCUMENTS_ROOT = "./html"

if __name__ == "__main__":
    main()
复制代码

多进程、线程实现http服务器

复制代码
 1 # -*- coding: utf-8 -*-
 2 # Time    : 2019/2/11 19:52
 3 # Author  : Mifen
 4 # Email   : 2952277346@qq.com
 5 # Software: PyCharm
 6 
 7 
 8 import socket
 9 import re
10 import threading
11 import multiprocessing
12 
13 
14 def handle_client(client_socket):
15     "为一个客户端进行服务"
16     recv_data = client_socket.recv(1024).decode('utf-8', errors="ignore")
17     request_header_lines = recv_data.splitlines()
18     for line in request_header_lines:
19         print(line)
20 
21     http_request_line = request_header_lines[0]
22     get_file_name = re.match("[^/]+(/[^ ]*)", http_request_line).group(1)
23     print("file name is ===>%s" % get_file_name)  # for test
24 
25     # 如果没有指定访问哪个页面。例如index.html
26     # GET / HTTP/1.1
27     if get_file_name == "/":
28         get_file_name = r'html/index.html'
29     else:
30         get_file_name = 'html' + get_file_name
31 
32     print("file name is ===2>%s" % get_file_name)  # for test
33 
34     try:
35         f = open(get_file_name, "rb")
36     except IOError:
37         # 404表示没有这个页面
38         response_headers = "HTTP/1.1 404 not found\r\n"
39         response_headers += "\r\n"
40         response_body = "====sorry ,file not found===="
41     else:
42         response_headers = "HTTP/1.1 200 OK\r\n"
43         response_headers += "\r\n"
44         response_body = f.read()
45         f.close()
46     finally:
47         # 因为头信息在组织的时候,是按照字符串组织的,不能与以二进制打开文件读取的数据合并,因此分开发送
48         # 先发送response的头信息
49         client_socket.send(response_headers.encode('utf-8'))
50         # 再发送body
51         client_socket.send(response_body)
52         client_socket.close()
53 
54 
55 def main():
56     "作为程序的主控制入口"
57     server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
58     server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
59     server_socket.bind(("192.168.43.227", 8080))
60     server_socket.listen(128)
61     while True:
62         client_socket, clien_cAddr = server_socket.accept()
63         t = threading.Thread(target=handle_client, args=(client_socket,))
64         t.start()
65         # 如果用多进程实现多任务,因为子进程已经复制了父进程的套接字等资源,所以父进程调用close不会将他们对应的这个链接关闭的
66         # client_socket.close()
67 
68 
69 # 这里配置服务器
70 DOCUMENTS_ROOT = "./html"
71 
72 if __name__ == "__main__":
73     main()
复制代码

二. Web并发服务器

gevent实现http服务器

复制代码
# -*- coding: utf-8 -*-
# Time    : 2019/2/11 20:06
# Author  : Mifen
# Email   : 2952277346@qq.com
# Software: PyCharm


import socket
import re
import gevent
from gevent import monkey
monkey.patch_all()

def handle_client(client_socket):
    "为一个客户端进行服务"
    recv_data = client_socket.recv(1024).decode('utf-8', errors="ignore")
    request_header_lines = recv_data.splitlines()
    for line in request_header_lines:
        print(line)

    http_request_line = request_header_lines[0]
    get_file_name = re.match("[^/]+(/[^ ]*)", http_request_line).group(1)
    print("file name is ===>%s" % get_file_name)  # for test

    # 如果没有指定访问哪个页面。例如index.html
    # GET / HTTP/1.1
    if get_file_name == "/":
        get_file_name = r'html/index.html'
    else:
        get_file_name = 'html' + get_file_name

    print("file name is ===2>%s" % get_file_name) #for test

    try:
        f = open(get_file_name, "rb")
    except IOError:
        # 404表示没有这个页面
        response_headers = "HTTP/1.1 404 not found\r\n"
        response_headers += "\r\n"
        response_body = "====sorry ,file not found===="
    else:
        response_headers = "HTTP/1.1 200 OK\r\n"
        response_headers += "\r\n"
        response_body = f.read()
        f.close()
    finally:
        # 因为头信息在组织的时候,是按照字符串组织的,不能与以二进制打开文件读取的数据合并,因此分开发送
        # 先发送response的头信息
        client_socket.send(response_headers.encode('utf-8'))
        # 再发送body
        client_socket.send(response_body)
        client_socket.close()


def main():
    "作为程序的主控制入口"
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_socket.bind(("192.168.43.227", 8080))
    server_socket.listen(128)
    while True:
        client_socket, clien_cAddr = server_socket.accept()
        gevent.spawn(handle_client,client_socket)

#这里配置服务器
DOCUMENTS_ROOT = "./html"

if __name__ == "__main__":
    main()
复制代码

epoll版的http服务器

复制代码
# -*- coding: utf-8 -*-
# Time    : 2019/2/11 22:01
# Author  : Mifen
# Email   : 2952277346@qq.com
# Software: PyCharm

import socket
import select

# 创建套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 设置可以重复使用绑定的信息
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

# 绑定本机信息
s.bind(("", 7788))

# 变为被动
s.listen(10)
# 创建一个epoll对象
epoll = select.epoll()  # epoll只能再Linux下运行

# 测试,用来打印套接字对应的文件描述符
# print(s.fileno())
# print(select.EPOLLIN|select.EPOLLET)

# 注册事件到epoll中
# epoll.register(fd[, eventmask])
# 注意,如果fd已经注册过,则会发生异常
# 将创建的套接字添加到epoll的事件监听中
epoll.register(s.fileno(), select.EPOLLIN | select.EPOLLET)

connections = {}
addresses = {}

# 循环等待客户端的到来或者对方发送数据
while True:

    # epoll 进行 fd 扫描的地方 -- 未指定超时时间则为阻塞等待
    epoll_list = epoll.poll()

    # 对事件进行判断
    for fd, events in epoll_list:

        # print fd
        # print events

        # 如果是socket创建的套接字被激活
        if fd == s.fileno():
            new_socket, new_addr = s.accept()

            print('有新的客户端到来%s' % str(new_addr))

            # 将 conn 和 addr 信息分别保存起来
            connections[new_socket.fileno()] = new_socket
            addresses[new_socket.fileno()] = new_addr

            # 向 epoll 中注册 新socket 的 可读 事件
            epoll.register(new_socket.fileno(), select.EPOLLIN | select.EPOLLET)

        # 如果是客户端发送数据
        elif events == select.EPOLLIN:
            # 从激活 fd 上接收
            recvData = connections[fd].recv(1024).decode("utf-8")

            if recvData:
                print('recv:%s' % recvData)
            else:
                # 从 epoll 中移除该 连接 fd
                epoll.unregister(fd)

                # server 侧主动关闭该 连接 fd
                connections[fd].close()
                print("%s---offline---" % str(addresses[fd]))
                del connections[fd]
                del addresses[fd]
复制代码

 

posted @   Amd794  阅读(209)  评论(0编辑  收藏  举报
编辑推荐:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示