一,http_python服务器

参看:http://www.cnblogs.com/vamei

代码皆复制教程内代码,保留作者署名。

当在浏览器中输入类似127.0.0.1:8000的url时,其实就是浏览器进程在和127.0.0.1服务器上的8000端口在通信。

socket是进程间通信的一种方法,socket有许多种类型,比如基于TCP协议或者UDP协议(两种网络传输协议)。

在互联网上,我们可以让某台计算机作为服务器。服务器开放自己的端口,被动等待其他计算机连接,当其他计算机作为客户,主动使用socket连接到服务器的时候,服务器就开始为客户提供服务。

HTTP协议基于TCP协议,但增加了更多的规范。这些规范,虽然限制了TCP协议的功能,但大大提高了信息封装和提取的方便程度。

一,简单进程TCP通信

在Python中,我们使用标准库中的socket包来进行底层的socket编程。

首先是服务器端,我们使用bind()方法来赋予socket以固定的地址和端口,并使用listen()方法来被动的监听该端口。当有客户尝试用connect()方法连接的时候,服务器使用accept()接受连接,从而建立一个连接的socket:

# Written by Vamei
# Server side
import socket

# Address
HOST = ‘‘
PORT = 8000

reply = ‘Yes‘

# Configure socket
s      = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))

# passively wait, 3: maximum number of connections in the queue
s.listen(3)
# accept and establish connection
conn, addr = s.accept()
# receive message
request    = conn.recv(1024)

print ‘request is: ‘,request
print ‘Connected by‘, addr
# send message
conn.sendall(reply)
# close connection
conn.close()

然后用另一台电脑作为客户,我们主动使用connect()方法来搜索服务器端的IP地址和端口,以便客户可以找到服务器,并建立连接:

# Written by Vamei
# Client side
import socket

# Address
HOST = ‘127.0.0.1‘
PORT = 8000

request = ‘can you hear me?‘

# configure socket
s       = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))

# send message
s.sendall(request)
# receive message
reply   = s.recv(1024)
print ‘reply is: ‘,reply
# close connection
s.close()

这样,先运行服务器程序,再运行客户端,就完成了一次进程间通信,这里每次通信建立的socket可以单纯创建出一个线程处理。

二,基于TCP socket的HTTP服务器

socket传输自由度太高,从而带来很多安全和兼容的问题。我们往往利用一些应用层的协议(比如HTTP协议)来规定socket使用规则,以及所传输信息的格式。

HTTP协议利用请求-回应(request-response)的方式来使用TCP socket。客户端向服务器发一段文本作为request,服务器端在接收到request之后,向客户端发送一段文本作为response。在完成了这样一次request-response交易之后,TCP socket被废弃。下次的request将建立新的socket。request和response本质上说是两个文本,只是HTTP协议对这两个文本都有一定的格式要求。

我们写出一个HTTP服务器端:

# Written by Vamei

import socket

# Address
HOST = ‘‘
PORT = 8000

# Prepare HTTP response
text_content = ‘‘‘HTTP/1.x 200 OK
Content-Type: text/html

<head>
<title>WOW</title>
</head>
<html>
<p>Wow, Python Server</p>
<IMG src="test.jpg"/>
</html>
‘‘‘

# Read picture, put into HTTP format
f = open(‘test.jpg‘,‘rb‘)
pic_content = ‘‘‘
HTTP/1.x 200 OK
Content-Type: image/jpg

‘‘‘
pic_content = pic_content + f.read()
f.close()

# Configure socket
s    = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))

# infinite loop, server forever
while True:
    # 3: maximum number of requests waiting
    s.listen(3)
    conn, addr = s.accept()
    request    = conn.recv(1024)
    method    = request.split(‘ ‘)[0]
    src            = request.split(‘ ‘)[1]

    # deal with GET method
    if method == ‘GET‘:
        # ULR
        if src == ‘/test.jpg‘:
            content = pic_content
        else: content = text_content

        print ‘Connected by‘, addr
        print ‘Request is:‘, request
        conn.sendall(content)
    # close connection
    conn.close()

客户端使用浏览器,访问127.0.0.1:8000,可以看到浏览器发送了两次请求,创建了2个socket,第一次是文本,第二次是图片。另外可以将while循环中的内容改为多进程或者多线程工作。

三,支持POST的基于TCP socket的HTTP服务器

修改服务器代码:

# Written by Vamei
# A messy HTTP server based on TCP socket 

import socket

# Address
HOST = ‘‘
PORT = 8000

text_content = ‘‘‘
HTTP/1.x 200 OK
Content-Type: text/html

<head>
<title>WOW</title>
</head>
<html>
<p>Wow, Python Server</p>
<IMG src="test.jpg"/>
<form name="input" action="/" method="post">
First name:<input type="text" name="firstname"><br>
<input type="submit" value="Submit">
</form>
</html>
‘‘‘

f = open(‘test.jpg‘,‘rb‘)
pic_content = ‘‘‘
HTTP/1.x 200 OK
Content-Type: image/jpg

‘‘‘
pic_content = pic_content + f.read()

# Configure socket
s    = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))

# Serve forever
while True:
    s.listen(3)
    conn, addr = s.accept()
    request    = conn.recv(1024)         # 1024 is the receiving buffer size
    method     = request.split(‘ ‘)[0]
    src        = request.split(‘ ‘)[1]

    print ‘Connected by‘, addr
    print ‘Request is:‘, request

    # if GET method request
    if method == ‘GET‘:
        # if ULR is /test.jpg
        if src == ‘/test.jpg‘:
            content = pic_content
        else: content = text_content
        # send message
        conn.sendall(content)
    # if POST method request
    if method == ‘POST‘:
        form = request.split(‘\r\n‘)
        idx = form.index(‘‘)             # Find the empty line
        entry = form[idx:]               # Main content of the request

        value = entry[-1].split(‘=‘)[-1]
        conn.sendall(text_content + ‘\n <p>‘ + value + ‘</p>‘)
        ######
        # More operations, such as put the form into database
        # ...
        ######
    # close connection
    conn.close()

这样,访问第一次得到页面,在页面内点击submit,将发起一次请求,这次是POST数据,然后处理,返回数据

四,使用SimpleHTTPServer包完成静态文件回应请求的http服务器

在使用SimpleHTTPServer之前,先使用SocketServer来架设服务器:

省略响应数据声明,

# This class defines response to each request
class MyTCPHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        # self.request is the TCP socket connected to the client
        request = self.request.recv(1024)

        print ‘Connected by‘,self.client_address[0]
        print ‘Request is‘, request

        method     = request.split(‘ ‘)[0]
        src        = request.split(‘ ‘)[1]

        if method == ‘GET‘:
            if src == ‘/test.jpg‘:
                content = pic_content
            else: content = text_content
            self.request.sendall(content)

        if method == ‘POST‘:
            form = request.split(‘\r\n‘)
            idx = form.index(‘‘)             # Find the empty line
            entry = form[idx:]               # Main content of the request

            value = entry[-1].split(‘=‘)[-1]
            self.request.sendall(text_content + ‘\n <p>‘ + value + ‘</p>‘)
            ######
            # More operations, such as put the form into database
            # ...
            ######

# Create the server
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
# Start the server, and work forever
server.serve_forever()

这里只不过是使用类来封装了操作。

SimpleHTTPServer可以用于处理GET方法和HEAD方法的请求。它读取request中的URL地址,找到对应的静态文件,分析文件类型,用HTTP协议将文件发送给客户。

创建index.html:

<head>
<title>WOW</title>
</head>
<html>
<p>Wow, Python Server</p>
<IMG src="test.jpg"/>
<form name="input" action="/" method="post">
First name:<input type="text" name="firstname"><br>
<input type="submit" value="Submit">
</form>
</html>

单独存储text.jpg文件。

改写Python服务器程序:

# Written by Vamei
# Simple HTTPsERVER

import SocketServer
import SimpleHTTPServer

HOST = ‘‘
PORT = 8000

# Create the server, SimpleHTTPRequestHander is pre-defined handler in SimpleHTTPServer package
server = SocketServer.TCPServer((HOST, PORT), SimpleHTTPServer.SimpleHTTPRequestHandler)
# Start the server
server.serve_forever()

这里,已经完成了静态http服务器的出现,免去了客户端请求的处理代码。这里的程序不能处理POST请求。我会在后面使用CGI来弥补这个缺陷。值得注意的是,Python服务器程序变得非常简单。将内容存放于静态文件,并根据URL为客户端提供内容,这让内容和服务器逻辑分离。

每次更新内容时,我可以只修改静态文件,而不用停止整个Python服务器。这些改进也付出代价。在原始程序中,request中的URL只具有指导意义,可以规定任意的操作。在SimpleHTTPServer中,操作与URL的指向密切相关。用自由度,换来了更加简洁的程序。

五,CGIHTTPServer:使用静态文件或者CGI来回应请求

CGIHTTPServer包中的CGIHTTPRequestHandler类继承自SimpleHTTPRequestHandler类,所以可以用来代替上面的例子,来提供静态文件的服务。此外,CGIHTTPRequestHandler类还可以用来运行CGI脚本。

CGI是服务器和应用脚本之间的一套接口标准。它的功能是让服务器程序运行脚本程序,将程序的输出作为response发送给客户。总体的效果,是允许服务器动态的生成回复内容,而不必局限于静态文件。

改写服务器代码:

# Written by Vamei
# A messy HTTP server based on TCP socket 

import BaseHTTPServer
import CGIHTTPServer

HOST = ‘‘
PORT = 8000

# Create the server, CGIHTTPRequestHandler is pre-defined handler
server = BaseHTTPServer.HTTPServer((HOST, PORT), CGIHTTPServer.CGIHTTPRequestHandler)
# Start the server
server.serve_forever()

修改index.html:

<head>
<title>WOW</title>
</head>
<html>
<p>Wow, Python Server</p>
<IMG src="test.jpg"/>
<form name="input" action="cgi-bin/post.py" method="post">
First name:<input type="text" name="firstname"><br>
<input type="submit" value="Submit">
</form>
</html>

创建一个cgi-bin的文件夹,并在cgi-bin中放入如下post.py文件,也就是我们的CGI脚本:

#!/usr/bin/env python

# Written by Vamei
import cgi
form = cgi.FieldStorage()

# Output to stdout, CGIHttpServer will take this as response to the client
print "Content-Type: text/html"     # HTML is following
print                               # blank line, end of headers
print "<p>Hello world!</p>"         # Start of content
print "<p>" +  repr(form[‘firstname‘]) + "</p>"

这样,就能根据URL索引到具体的静态页面或者CGI脚本文件,基本实现了HTTP服务器。

综上,这一起都是基于socket来手动完成的,即使是后面使用上层库,处理请求还是只能简单的返回数据。在此之上,如果既能自动返回静态文件和运行CGI文件,又能插手到URL的处理中,让URL不再单纯的是文件索引地址,而是可处理的就好了。在“二,使用框架完成http_python服务器”中丰富这个demo。

时间: 2024-08-01 17:50:13

一,http_python服务器的相关文章

Sqlserver通过链接服务器访问Oracle的解决办法

转自http://blog.sina.com.cn/s/blog_614b6f210100t80r.html 一.创建sqlserver链接服务(sqlserver链接oracle)  首先sqlserver 链接oracle可以通过两个访问接口: “MSDAORA” 和“OraOLEDB.Oracle” 1.“MSDAORA”访问接口是由Microsoft OLE DB Provider for Oracle提供的,这里建议不使用此接口进行链接.通过该访问接口建立的链接服务器在进行查询orac

XShell 连接虚拟机中的服务器 失败 、连接中断(Connection closed by foreign host.)

在使用XShell连接虚拟机中的服务器时,报以下错误并断开连接,之前连接还是挺稳定的,忽然就这样了 Last login: Thu Aug 10 21:28:38 2017 from 192.168.1.102 [[email protected] ~]# Socket error Event: 32 Error: 10053. Connection closing...Socket close. Connection closed by foreign host. Disconnected f

通过SoftEther VPN自建VPN服务器

SoftEther VPN是日本政府的研究和开发项目的一项工作,由日本的经济.贸易和工业部资助,由信息化推进机构管理.SoftEther VPN在日本筑波大学开发的免费软件.具有终极兼容许多设备的高性能VPN.支持Windows.Mac.智能手机.平板电脑(iPhone\iPad\Android\WindowsRT)和思科或其他VPN路由器.SoftEther VPN也接受OpenVPN和MS-SSTP VPN客户端. 可以从http://www.softether-download.com/(

微信开发之本地接口调试(非80端口,无需上传服务器服务器访问

前言: 本文是总结在开发微信接口时,为方便开发所采取的一些快捷步骤,已节省开发人员难度开发时间从而提高开发效率. 本地测试: (提醒,在本地模拟微信get或post数据时先将校验参数注释掉) 利用微信模拟器weixinPost进行模拟发送xml数据 由于这个软件是微信没公开高级接口时公布的,所以对于高级接口的调试,笔者利用的是Fiddler这个抓包工具模拟post数据 高端测试: 利用反向代理软件ngrok访问本地项目: ngrok 是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之

pfsense Web服务器负载平衡配置示例

在pfsense的网关和服务器中有两种类型的负载平衡功能.网关负载平衡可以通过多个WAN连接分发Internet绑定的流量.服务器负载平衡管理传入流量,因此它利用多个内部服务器进行负载分配和冗余,服务器负载平衡允许流量在多个内部服务器之间分配,它最常用于Web服务器和SMTP服务器.下面我们就以实例来介绍服务器负载平衡的设置. 下面介绍如何通过pfsense2.32配置Web服务器的负载平衡. 网络环境 服务器负载平衡示例网络环境 上图为示例网络环境.它由单个防火墙组成,使用其WAN IP地址池

部署AlwaysOn第一步:搭建Windows服务器故障转移集群

在Windows Server 2012 R2 DataCenter 环境中搭建集群之前,首先要对Windows服务器故障转移集群(Windows Server Failover Cluster,简称WSFC)有基本的了解.WSFC必须部署在域管理环境中,由多台服务器组成,每台服务器称作一个"结点"(Node),每个结点上都运行了Windows服务器故障转移集群服务,整个集群系统允许部分结点掉线.故障或损坏而不影响整个系统的正常运作.集群自动检测结点的健康状态,一旦活跃结点发生异常,变

如何将Win7做为NTP服务器

1. 修改注册表项 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer Enabled 设定为 1(默认0) HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config\ AnnounceFlags 设定为 5 (默认 10) Value Meaning 0 Timeserv_Announce_No, R

win7搭建局域网时间服务器

近日,本人想在局域网内通过普通的windows 7 PC搭建一台NTP服务器,可看似简单的配置却给我捣腾了了半天.初期,参考了互联网的上相关的配置文档,可网络设备就是死活不同步NTP服务器的时间.实在没办法,只有通过来抓包分析了,经过一番研究后,终于找到问题,现将这个文档与大家分享: 通过windows系统为局域网搭建NTP服务器,为局域网内网络设备提供时间服务,经过测试,使用于windows xp.windows 2003.windows 7. 1.启用 NTPServer.为此,请按照下列步

C# 远程服务器 安装、卸载 Windows 服务,读取远程注册表,关闭杀掉远程进程

这里安装windows服务我们用sc命令,这里需要远程服务器IP,服务名称.显示名称.描述以及执行文件,安装后需要验证服务是否安装成功,验证方法可以直接调用ServiceController来查询服务,也可以通过远程注册表来查找服务的执行文件:那么卸载文件我们也就用SC命令了,卸载后需要检测是否卸载成功,修改显示名称和描述也用sc命令.至于停止和启动Windows服务我们可以用sc命令也可以用ServiceController的API,当停止失败的时候我们会强制杀掉远程进程,在卸载windows