MENU

用socket撸一个简易web服务器

• March 3, 2019 • Read: 147 • python

最近几天学习了socket网络编程以及多进程多线程和协程,感觉收获颇丰。然后自己撸了一个简易的web服务器,能够返回一个静态页。分别用进程,线程和协程撸了一遍,加深记忆。

从pt站里下载的某培训机构的网课,100多G。先下载到大盘鸡里然后上传到百度网盘里了,需要的话给我发邮件,毕竟算是侵权了,就不光明正大的分享了。

1


2


html格式的学习资料我分享(链接:https://share.weiyun.com/5SBjYPv)一下,直接用浏览器打开index.html即可,如图:

3

我写的代码及用到的html静态页资料我分享一下:链接:https://share.weiyun.com/5C7l6uL

代码

普通版

import socket
import re

def response_data(client_socket):

    #接收数据
    recv_data=client_socket.recv(1024)

    #解码并打印请求头
    print('接收数据类型:',type(recv_data))
    print(recv_data.decode('utf8'))

    #检查请求头信息
    a_file=re.split(r' | \n',str(recv_data.decode('utf8')))[1]
    if str(a_file)=='/':
        a_file+='index.html' 
    file_name='./html'+a_file
    print('文件名:',file_name)

    #二进制可读打开文件
    try:
        with open(file=file_name,mode='rb') as f:
            content=f.read()
        #构建响应头信息
        response_header='HTTP/1.1 200 OK '+'\n'+'\n'
    except :
        content=("-"*20+"404  FILE NOT FOUND"+'-'*20).encode()
        #构建响应头信息
        response_header='HTTP/1.1 404 FILE NOT FOUND'+'\n'+'\n'

    #返回给浏览器信息
    #通过utf8编码为二进制
    print('响应头类型:',type(response_header))


    #socket通过二进制传输数据
    client_socket.send(response_header.encode('utf8'))
    client_socket.send(content)

    client_socket.close()


def main():
    #创建tcp_server_socket
    tcp_server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    #绑定端口
    tcp_server_socket.bind(('',80))

    #创建监听
    tcp_server_socket.listen(128)


    while True:

        #等待连接
        client_socket,client_addr= tcp_server_socket.accept()
        response_data(client_socket)

    tcp_server_socket.close()

if __name__ == '__main__':

    main()

多进程版

import socket
import re
import multiprocessing

 
def response_data(client_socket):

    #接收数据
    recv_data=client_socket.recv(1024)

    #解码并打印请求头
    print('接收数据类型:',type(recv_data))
    print(recv_data.decode('utf8'))

    #检查请求头信息
    a_file=re.split(r' | \n',str(recv_data.decode('utf8')))[1]
    if str(a_file)=='/':
        a_file+='index.html' 
    file_name='./html'+a_file
    print('文件名:',file_name)

    #二进制可读打开文件
    try:
        with open(file=file_name,mode='rb') as f:
            content=f.read()
        #构建响应头信息
        response_header='HTTP/1.1 200 OK '+'\n'+'\n'
    except :
        content=("-"*20+"404  FILE NOT FOUND"+'-'*20).encode()
        #构建响应头信息
        response_header='HTTP/1.1 404 FILE NOT FOUND'+'\n'+'\n'

    #返回给浏览器信息
    #通过utf8编码为二进制
    print('响应头类型:',type(response_header))


    #socket通过二进制传输数据
    client_socket.send(response_header.encode('utf8'))
    client_socket.send(content)

    client_socket.close()


def main():
    #创建tcp_server_socket
    tcp_server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    #绑定端口
    tcp_server_socket.bind(('',80))

    #创建监听
    tcp_server_socket.listen(128)


    while True:

        #等待连接
        client_socket,client_addr= tcp_server_socket.accept()
        #多进程
        p= multiprocessing.Process(target=response_data,args=(client_socket,))
        #response_data(client_socket)
        p.start()
        #对照linux硬链接  
        #https://www.jianshu.com/p/dde6a01c4094
        client_socket.close()

    tcp_server_socket.close()

if __name__ == '__main__':

    main()

多线程版

import socket
import re
import threading


def response_data(client_socket):

    #接收数据
    recv_data=client_socket.recv(1024)

    #解码并打印请求头
    print('接收数据类型:',type(recv_data))
    print(recv_data.decode('utf8'))

    #检查请求头信息
    a_file=re.split(r' | \n',str(recv_data.decode('utf8')))[1]
    if str(a_file)=='/':
        a_file+='index.html' 
    file_name='./html'+a_file
    print('文件名:',file_name)

    #二进制可读打开文件
    try:
        with open(file=file_name,mode='rb') as f:
            content=f.read()
        #构建响应头信息
        response_header='HTTP/1.1 200 OK '+'\n'+'\n'
    except :
        content=("-"*20+"404  FILE NOT FOUND"+'-'*20).encode()
        #构建响应头信息
        response_header='HTTP/1.1 404 FILE NOT FOUND'+'\n'+'\n'

    #返回给浏览器信息
    #通过utf8编码为二进制
    print('响应头类型:',type(response_header))


    #socket通过二进制传输数据
    client_socket.send(response_header.encode('utf8'))
    client_socket.send(content)

    client_socket.close()


def main():
    #创建tcp_server_socket
    tcp_server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    #绑定端口
    tcp_server_socket.bind(('',80))

    #创建监听
    tcp_server_socket.listen(128)


    while True:

        #等待连接
        client_socket,client_addr= tcp_server_socket.accept()

        t=threading.thread(target=response_data,args=(client_socket,))
        t.start()
        #response_data(client_socket)

        #关闭监听套接字
    tcp_server_socket.close()

if __name__ == '__main__':

    main()

协程高并发版本

import socket
import re
from gevent import monkey
import gevent

monkey.patch_all()
def response_data(client_socket):

    #接收数据
    recv_data=client_socket.recv(1024)

    #解码并打印请求头
    print('接收数据类型:',type(recv_data))
    print(recv_data.decode('utf8'))

    #检查请求头信息
    a_file=re.split(r' | \n',str(recv_data.decode('utf8')))[1]
    if str(a_file)=='/':
        a_file+='index.html' 
    file_name='./html'+a_file
    print('文件名:',file_name)

    #二进制可读打开文件
    try:
        with open(file=file_name,mode='rb') as f:
            content=f.read()
        #构建响应头信息
        response_header='HTTP/1.1 200 OK '+'\n'+'\n'
    except :
        content=("-"*20+"404  FILE NOT FOUND"+'-'*20).encode()
        #构建响应头信息
        response_header='HTTP/1.1 404 FILE NOT FOUND'+'\n'+'\n'

    #返回给浏览器信息
    #通过utf8编码为二进制
    print('响应头类型:',type(response_header))


    #socket通过二进制传输数据
    client_socket.send(response_header.encode('utf8'))
    client_socket.send(content)

    client_socket.close()


def main():
    #创建tcp_server_socket
    tcp_server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

    #绑定端口
    tcp_server_socket.bind(('',80))

    #创建监听
    tcp_server_socket.listen(128)


    while True:

        #等待连接
        client_socket,client_addr= tcp_server_socket.accept()
        g=gevent.spawn(response_data,client_socket)
        g.join()
        #response_data(client_socket)

    tcp_server_socket.close()

if __name__ == '__main__':

    main()

理论上多协程高并发是最给力的,然后我把多协程版的放在我的腾讯云学生机上跑了一下

111.231.102.149:8888

可以测试一下结果。

Tags: python
Archives QR Code Tip
QR Code for this page
Tipping QR Code