python实现简单的web服务器

本文介绍了一个简单的Python Web服务器实现方案,用于接收客户端上报的数据,并支持gzip压缩。服务器能够解析请求参数,根据IMEI号创建文件夹,将相同开始时间的数据视为同一批次,并保存每个URL的跳转记录。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近有需求需要提供一个简单的 web 服务器,用于客户端上报一些内容,采用 post 方式上报并支持 gzip 压缩,代码如下:


#!python
#-*- coding:utf-8 -*-
'''
    上报数据用 gzip 压缩了,所以用 http 服务器接收数据并输出接收到的数据
'''

import SimpleHTTPServer
import SocketServer
import StringIO, gzip
import urllib, time
import socket
import logging
import os

PORT = 10006

from logging.handlers import TimedRotatingFileHandler
logger = logging.getLogger('report')
logger.setLevel(logging.DEBUG)
## 只保存过去7天的日志,按天创建新的日志
handler = TimedRotatingFileHandler('log/timed.log',
                                   when = 'midnight',
                                   interval=1,
                                   backupCount=7)
fmt = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(fmt=fmt)
logger.addHandler(handler)


class myHttpServer(SimpleHTTPServer.SimpleHTTPRequestHandler):
    def do_GET(self):
        logStr = ('\n%s %s %s\r\n%s' % (self.command, self.path, self.request_version, str(self.headers)))
        logger.warn('%s\r\n' % logStr)
        self.send_response(200)
        self.end_headers()
    def do_POST(self):
        '''接收上报的文件,参数为:
            imei=xxx&startTime=timestamp&urlNum=1&url=xxx&thisTime=now
            使用 gzip 上报,接收到上报文件后,按照 imei 创建文件夹;
            相同的 startTime 表示是同一次请求的数据;
            urlNum 表示是该次请求的第几次跳转,每次跳转会是一个新的文件;
            url表示本次url;
            thisTime 表示本次请求的开始时间;
            最终保存结果如下:
                                            +-- urlNum_thisTime.gzip
                          |-- startTime ——|-- urlNum_thisTime.gzip
                          |                 +-- readme.txt  每个文件上传ip,开始时间,对应的 url
                imei ——-|

                ip: xxx
                startTime: xxx
                url: xxx
                ------
        '''
        global logger
        clientIp = self.client_address
        # 解析参数
        uri = self.path
        try:
            tmpUrlParam = uri.split('?')[1]
            tmpUrlParam = tmpUrlParam.split('&')
            urlParam = {'imei': '', 'url': '', 'startTime': '', 'thisTime': '', 'urlNum': '', 'offer':''}
            for kv in tmpUrlParam:
                tmpArr = kv.split('=')
                urlParam[tmpArr[0]] = tmpArr[1]
            for key in urlParam:
                if not urlParam[key]:
                    logger.error("\nclientIp = %s, uri = %s, is wrong" % (clientIp, uri))
                    self.errorResponse('parameter %s is empty' % key)
        except Exception, e:
            logger.error("uri = %s, analyse error" % uri)
            self.errorResponse('parameter error')
            return

        # 判断文件是否已存在,已存在则添加到后面,否则新建文件
        filePath = os.path.join(urlParam['imei'], urlParam['startTime'], urlParam['urlNum'] + '_' + urlParam['thisTime'] + '.zip')
        # 文件已经存在,则添加到文件末尾
        if os.path.isfile(filePath):
            fp = open(filePath, 'ab')
        else:
            ## 文件不存在表示这个该文件第一个数据包,新建文件并添加记录到 readme.txt
            dirName = os.path.dirname(filePath)
            if not os.path.isdir(dirName):
                os.makedirs(dirName)
            fp = open(filePath, 'ab+')

            readmePath = os.path.join(dirName, 'readme.txt')
            if os.path.isfile(readmePath):
                tmpfp = open(readmePath, 'a')
            else:
                tmpfp = open(readmePath, 'a+')
            now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
            tmpContent = 'ip: %s\nstartTime: %s\nurl: %s\noffer: %s\n\n' % (str(clientIp), now, urllib.unquote(urlParam['url']), urllib.unquote(urlParam['offer']))
            tmpfp.write(tmpContent)
            tmpfp.close()

        # 获取本次上报数据
        length = int(self.headers.getheader('content-length'))
        qs = self.rfile.read(length)
        compressMethod = self.headers.get('Accept-Encoding', "")
        if compressMethod == 'gzip':
            try:
                compressedData = StringIO.StringIO(qs)
                gziper = gzip.GzipFile(fileobj=compressedData)
                content = gziper.read()
                fp.write(content)
                fp.close()
            except Exception, e:
                self.errorResponse('uncompress data failed')
                logStr = '\nuncompress gzip failed[clientIp: %s]: %s\n' % (clientIp, str(e))
                logStr += 'data is:%s' % qs
                logger.error(logStr)
                return
            finally:
                if not fp.closed:
                    fp.close()
        else:
            fp.write(qs)
            fp.close()
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        self.finish()

    def errorResponse(self, msg):
        self.send_response(400)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        self.wfile.write(msg)
        self.finish()


def main():
    global PORT
    socket.setdefaulttimeout(45)
    handler = myHttpServer
    httpd = SocketServer.TCPServer(("", PORT), handler)
    httpd.serve_forever()


if __name__ == '__main__':
    main()

经实际使用,对不高的并发处理完全可以应付。这种自定义的上报工作,要是用其他语言来写不知道可以怎么实现


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值