Python实现简单的HttpServer服务器示例


Posted in Python onSeptember 25, 2017

要写一个类似tomcat的简易服务器,首先需弄清楚这几点:

1. 客户端(Client)和服务端(Server)的角色及作用

角色A向角色B请求数据,这时可以把A视为客户端,B视为服务端。客户端的主要职责是发送请求和接收服务端根据自己发送的请求返回的请求信息,而服务端的主要职责是接收请求和返回请求数据。

2. 浏览器是什么及工作原理

我们常说B/S,C/S架构,所谓的B/S指browser/server,C/S指Client/Server,B/S架构其实就是应用于浏览器的程序,只要最后在浏览器上展现的都是 B/S架构,而非在浏览器上展现的都是C/S架构,如常见的英雄联盟游戏。但是本质上只有C/S架构,因为浏览器是一种特殊的客户端。

浏览器的特殊之处是有一下三大引擎:

  • DOM解析引擎:即浏览器可以解析HTML
  • 样式解析引擎:即浏览器可以解析CSS
  • 脚本解析引擎:即浏览器可以解析JAVASCRIPT

3. Socket

上面提到的客户端服务端,他们之间是怎样实现连接及数据传递的,这就是Socket,每一门编程语言都有Socket编程,Socket的作用就是提供了网络通信的能力

4. HTTP协议及HTTP与TCP/TP的区别

客户端和服务端通过Socket实现了网络通信的能力,可以实现数据传递。而协议是规范数据传输,也就是说客户端和服务端之间传输数据要按照一定得规范和标准传输,不能瞎传。

TCP/IP(Transmission Control Protocol/Internet Protocol):传输控制协议/网间协议

HTTP(HyperText Transfer Protocol):超文本传输协议。

TCP/TP的区别:

做一个形象的比喻,TCP/TP是马路,HTTP则是马路上的汽车,所以HTTP一定是在TCP/TP的基础上的。

HTTP主要是应用在web程序上,设计之初就是为了提供一种发布和接收HTML页面的方法,这样说可能很抽象很难理解。具体的说当我们去访问一个网站时,只需要拿到基于这个网站的内容(比如html,css,JavaScript)。但我们抓取浏览器接收到的资源包(可以用Fiddler工具)发现除了网页需要的实体内容还有一些下面信息:

HTTP/1.1 200 OK
 Cache-Control: private
 Content-Type: text/plain; charset=utf-8
 Content-Encoding: gzip
 Vary: Accept-Encoding
 Server: Microsoft-IIS/7.5
 X-AspNet-Version: 4.0.30319
 X-Powered-By: ASP.NET
 Date: Tue, 24 Jan 2017 03:25:23 GMT
 Connection: close
 Content-Length: 661

这就是http协议规范,比如Content-Type就是说传输的时候文件的格式,Content-Encoding规定了编码格式。不止以上这些,非常多,关于这些参数含义这里就不去一一介绍

5. URL的含义

URL(统一资源定位符),就是我们常说的网址,直接来解析一个URL来说明他:http://198.2.17.25:8080/webapp/index.html

这个含义是找到IP为198.2.17.25的服务器下目录为webapp的index.html

但是我们常看到的是这样的URL:http://goodcandle.cnblogs.com/archive/2005/12/10/294652.aspx

其实这个和上面的一样,不过这里存在一个域名解析,可以将goodcandle.cnblogs.com解析成对应的IP地址

弄清楚以上五点之后开始来写代码

webServer.py

import socket
import sys
import getFileContent
#声明一个将要绑定的IP和端口,这里是用本地地址
server_address = ('localhost', 8080)
class WebServer():
  def run(self):
    print >>sys.stderr, 'starting up on %s port %s' % server_address
    #实例化一个Socket
    sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #绑定IP和端口
    sock.bind(server_address)
    #设置监听
    sock.listen(1)
    #这里首先给个死循环,其实这里是需要多线程的,再后续版本将会实现
    while True:
      #接受客户端的请求并得到请求信息和请求的端口信息
      connection, client_address = sock.accept()
      print >>sys.stderr, 'waiting for a connection'
      try:
        #获取请求信息
        data = connection.recv(1024)
        if data:
          #发送请求信息
          connection.sendall(getFileContent.getHtmlFile(data))
      finally:
        connection.close()

if __name__ == '__main__':
  server=WebServer()
  server.run()

webServer.py很清晰简洁,connection.sendall()服务端返回信息给浏览器,但是发送的数据必须遵循HTTP协议规范
getFileContent.py是对发送的数据进行HTTP协议规范处理

import sys
import os

#得到要发送的数据信息
def getHtmlFile(data):
  msgSendtoClient=""
  requestType=data[0:data.find("/")].rstrip()
  #判断是GET请求还是POST请求
  if requestType=="GET":
    msgSendtoClient=responseGetRequest(data,msgSendtoClient)
  if requestType=="POST":
    msgSendtoClient=responsePostRequest(data,msgSendtoClient)
  return msgSendtoClient

#打开文件,这里不直接写,二是去取要发送的文件再写
def getFile(msgSendtoClient,file):
    for line in file:
     msgSendtoClient+=line
    return msgSendtoClient

#筛选出请求的一个方法
def getMidStr(data,startStr,endStr):
  startIndex = data.index(startStr)
  if startIndex>=0:
    startIndex += len(startStr)
    endIndex = data.index(endStr)
    return data[startIndex:endIndex]

#获取要发送数据的大小,根据HTTP协议规范,要提前指定发送的实体内容的大小
def getFileSize(fileobject):
  fileobject.seek(0,2)
  size = fileobject.tell()
  return size

#设置编码格式和文件类型
def setParaAndContext(msgSendtoClient,type,file,openFileType):
  msgSendtoClient+="Content-Type: "+type+";charset=utf-8"
  msgSendtoClient+="Content-Length: "+str(getFileSize(open(file,"r")))+"\n"+"\n"
  htmlFile=open(file,openFileType)
  msgSendtoClient=getFile(msgSendtoClient,htmlFile)
  return msgSendtoClient

#GET请求的返回数据
def responseGetRequest(data,msgSendtoClient):
  return responseRequest(getMidStr(data,'GET /','HTTP/1.1'),msgSendtoClient)

#POST请求的返回数据
def responsePostRequest(data,msgSendtoClient):
  return responseRequest(getMidStr(data,'POST /','HTTP/1.1'),msgSendtoClient)

#请求返回数据
def responseRequest(getRequestPath,msgSendtoClient):
  headFile=open("head.txt","r")
  msgSendtoClient=getFile(msgSendtoClient,headFile)
  if getRequestPath==" ":
    msgSendtoClient=setParaAndContext(msgSendtoClient,"text/html","index.html","r")
  else:
    rootPath=getRequestPath
    if os.path.exists(rootPath) and os.path.isfile(rootPath):
      if ".html" in rootPath:
        msgSendtoClient=setParaAndContext(msgSendtoClient,"text/html",rootPath,"r")
      if ".css" in rootPath:
        msgSendtoClient=setParaAndContext(msgSendtoClient,"text/css",rootPath,"r")
      if ".js" in rootPath:
        msgSendtoClient=setParaAndContext(msgSendtoClient,"application/x-javascript",rootPath,"r")
      if ".gif" in rootPath:
        msgSendtoClient=setParaAndContext(msgSendtoClient,"image/gif",rootPath,"rb")
      if ".doc" in rootPath:
        msgSendtoClient=setParaAndContext(msgSendtoClient,"application/msword",rootPath,"rb")
      if ".mp4" in rootPath:
        msgSendtoClient=setParaAndContext(msgSendtoClient,"video/mpeg4",rootPath,"rb")
    else:
      msgSendtoClient=setParaAndContext(msgSendtoClient,"application/x-javascript","file.js","r")
  return msgSendtoClient

Github源码下载:https://github.com/Jiashengp/Python_httpServer

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
使用 Python 获取 Linux 系统信息的代码
Jul 13 Python
python安装以及IDE的配置教程
Apr 29 Python
Python增量循环删除MySQL表数据的方法
Sep 23 Python
Python基础教程之tcp socket编程详解及简单实例
Feb 23 Python
python3+PyQt5使用数据库窗口视图
Apr 24 Python
Windows下Anaconda2安装NLTK教程
Sep 19 Python
Python对excel文档的操作方法详解
Dec 10 Python
python使用pipeline批量读写redis的方法
Feb 18 Python
解决python3插入mysql时内容带有引号的问题
Mar 02 Python
python自动从arxiv下载paper的示例代码
Dec 05 Python
python re模块和正则表达式
Mar 24 Python
python 中[0]*2与0*2的区别说明
May 10 Python
Python使用正则表达式过滤或替换HTML标签的方法详解
Sep 25 #Python
Python实现的破解字符串找茬游戏算法示例
Sep 25 #Python
Python实现破解猜数游戏算法示例
Sep 25 #Python
Python基于identicon库创建类似Github上用的头像功能
Sep 25 #Python
python3使用requests模块爬取页面内容的实战演练
Sep 25 #Python
python中通过预先编译正则表达式提高效率
Sep 25 #Python
python之Character string(实例讲解)
Sep 25 #Python
You might like
如何开发一个虚拟域名系统
2006/10/09 PHP
PHP 字符串编码截取函数(兼容utf-8和gb2312)
2009/05/02 PHP
PHP+Apache+Mysql环境搭建教程
2016/08/01 PHP
PHP定义字符串的四种方式详解
2018/02/06 PHP
php strftime函数获取日期时间(switch用法)
2018/05/16 PHP
PHP使用 Imagick 扩展实现图片合成,圆角处理功能示例
2019/09/09 PHP
js检测客户端不是firefox则提示下载
2007/04/07 Javascript
读JavaScript DOM编程艺术笔记
2011/11/15 Javascript
基于javascript滚动图片具体实现
2013/11/18 Javascript
Chrome下ifame父窗口调用子窗口的问题示例探讨
2014/03/17 Javascript
jQuery使用ajaxSubmit()提交表单示例
2014/04/04 Javascript
jQuery.each使用详解
2015/07/07 Javascript
JS组件Bootstrap Select2使用方法详解
2020/04/17 Javascript
利用JS生成博文目录及CSS定制博客
2016/02/10 Javascript
深入理解JavaScript中的浮点数
2016/05/18 Javascript
BootStrap实现手机端轮播图左右滑动事件
2016/10/13 Javascript
jQuery之动画效果大全
2016/11/09 Javascript
vue.js异步上传文件前后端实现代码
2017/08/22 Javascript
React 组件转 Vue 组件的命令写法
2018/02/28 Javascript
JavaScript寄生组合式继承原理与用法分析
2019/01/11 Javascript
Vue中CSS动画原理的实现
2019/02/13 Javascript
微信小程序之onLaunch与onload异步问题详解
2019/03/28 Javascript
基于ajax实现上传图片代码示例解析
2020/12/03 Javascript
[02:49]2018DOTA2亚洲邀请赛主赛事决赛日战况回顾 Mineski鏖战5局夺得辉耀
2018/04/10 DOTA
在Python中操作字典之setdefault()方法的使用
2015/05/21 Python
13个最常用的Python深度学习库介绍
2017/10/28 Python
Python中extend和append的区别讲解
2019/01/24 Python
python 中的列表生成式、生成器表达式、模块导入
2019/06/19 Python
Python内置函数property()如何使用
2020/09/01 Python
网络方面基础面试题
2012/11/16 面试题
创业计划书六个要素
2013/12/26 职场文书
证婚人搞笑证婚词
2014/01/10 职场文书
大二学生学习个人自我评价
2014/01/19 职场文书
工程招投标邀请书
2014/01/26 职场文书
离婚协议书怎样才有法律效力
2014/10/10 职场文书
Jupyter notebook 更改文件打开的默认路径操作
2021/05/21 Python