python实现WebServer(Socket)

python实现WebServer(Socket)

本题主要解答了《计算机网络》的第二章编程题的第一个作业。

V1

要求:用Python开发一个简单的Web服务器,仅能处理一个请求。(1)当一个Client连接时创建一个Socket;(2)从这个连接接受HTTP请求;(3)解释该请求以确定所请求得特定文件;(4)从Server得文件系统获得请求得文件;(5)创建一个由请求得文件组成得响应报文;(6)经TCP连接向请求的浏览器发送响应。如果浏览器请求一个不存在的文件,Server应当返回一个“404 Not Found”的差错报码。

from socket import *
import sys #In order to terminate the program

serverSocket = socket(AF_INET, SOCK_STREAM)
# Prepare a server socket
serverPort = 6789
serverSocket.bind(("", serverPort))
serverSocket.listen(1)

while True:
    # Establish the connection
    print('Ready ro serve...')
    connectionSocket, addr = serverSocket.accept()
    try:
        message = connectionSocket.recv(2048).decode()
        filename = message.split()[1]
        f = open(filename[1:])
        outputdata = f.readlines()
        # Send one HTTP header line into socket
        OkMSG = "HTTP/1.1 200 OK \r\n\r\n"
        connectionSocket.send(OkMSG.encode())
        # Send the content of the requsted file to the Client
        for i in range(0, len(outputdata)):
            connectionSocket.send(outputdata[i].encode())
        connectionSocket.send("\r\n".encode())

        connectionSocket.close()

    except IOError:
        # Send response message for file not found
        ErrMSG = 'HTTP/1.1 404 Not Found \r\n\r\n'
        connectionSocket.send(ErrMSG.encode())
        connectionSocket.send("<html><head></head><body><h1>404 Not Found</h1></body></html>\r\n".encode())
        # Close client socket
        connectionSocket.close()

serverSocket.close()
sys.exit()

运行:

  1. 在命令行中输入ipconfig(Windows)或者ifconfig(Linux)查看IP地址,或者使用回环地址127.0.0.1;
  2. 运行上述代码;
  3. 在浏览器中输入:http://IP地址:端口号/文件名。例如:http://192.168.121.131:6789/helloworld.html,搜索即可。

注意点:

  • html文件和py文件放在同一路径下(同一文件夹里)
  • 读文件时read和readlines效果不同,具体可以上网查
  • 我在pycharm运行时split那里会报错“list index out of range”,但在Ubuntu系统中不会有这个问题,可能是操作系统后者环境的配置出了问题?
  • 有些人运行会出gdk的报错,这时候修改read为readlines或者去掉message接收消息时的decode()可能会有用。但至于为什么还不清楚。
  • 有人在Linux里面运行时,输入不存在的文件进行搜索不会显示“404 Not Found”,原因是你用python命令运行的代码,而一些Ubuntu的版本终端内置的是python2,而python2和python3有很多不兼容,这时候用python3运行就没有问题了。

改进(V2)

目前,网络服务器一次只处理一个HTTP请求。实现能够同时服务多个请求的多线程服务器。使用线程,首先创建一个主线程,其中修改后的服务器在固定端口侦听客户端。当它接收到来自客户端的TCP连接请求时,它将通过另一个端口设置TCP连接,并在一个单独的线程中服务于客户端请求。每个请求/响应对在单独的线程中将有一个单独的TCP连接。

# import socket module
from socket import *
import threading
import sys #In order to terminate the program

def msg_handle(connectionSocket, addr):
    try:
        print('A client connected...')
        msg = connectionSocket.recv(2048).decode()
        filename = msg.split()[1]
        f = open(filename[1:])
        outputdata = f.readlines()
        connectionSocket.send("HTTP/1.1 200 OK \r\n\r\n".encode())
        for i in range(0, len(outputdata)):
            connectionSocket.send(outputdata[i].encode())
        connectionSocket.send("\r\n".encode())
        connectionSocket.close()
    except IOError:
        connectionSocket.send("HTTP/1.1 404 Not Found \r\n\r\n".encode())
        connectionSocket.send("<html><head></head><body><h1>404 Not Found</h1></body></html>\r\n".encode())
        connectionSocket.close()

def init():
    global serverSocket
    serverSocket = socket(AF_INET, SOCK_STREAM)
    serverSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    serverPort = 6677
    serverSocket.bind(('', serverPort))
    serverSocket.listen(5)
    print('Ready to serve...')


def accept_client():
    while True:
        connectionSocket, addr = serverSocket.accept()
        cthread = threading.Thread(target = msg_handle, args = (connectionSocket, addr))
        cthread.start()


if __name__ == '__main__':
    init()
    sthread = threading.Thread(target = accept_client)
    sthread.start()
    sys.exit()

V1和V2在Ubuntu里运行时都有一个问题,会报错:

OSError: [Errno 98] Address already in use

此时用下列命令查看:

netstat -tunlp

会看到:
在这里插入图片描述
再用 kill -9 16012(进程号)杀死进程即可。
出错的原因是上次终止代码运行使用了CTRL+z来暂停运行,而采用CTRL+C来停止就没有这个问题了。

V1和V2还有另外一个问题,好像只有本机的浏览器可以访问。我用手机就访问不到了。访问设备和运行代码的设备必须在同一局域网下才能进行连接。据说是IP地址的原因,因为我们查到的IP地址并不是“真正的IP地址”,相关的知识另外了解吧。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值