1.源代码
#!/usr/bin/env python
# coding=utf8
# si.hairui, 2016.11.24
# Http Client, Python 2.7.5
# ---------------------------------------------
# 1.上电之后读取配置文件,获取客户端列表和服务器列表;
# 2.校验配置文件中客户端IP的真实性(有效性);
# 3.解析服务端URL字段内容
# 4.注册线程,开始并发请求
# ---------------------------------------------
# ---------------------------------------------
# 模块导入
# ---------------------------------------------
import socket
import httplib
# ---------------------------------------------
# 全局变量
# ---------------------------------------------
# 打印开关
PRINT_SW = 0 # 0-关,1-开
# 客户端信息列表
HTTP_CLIENT_LIST = []
'''
HTTP_CLIENT_LIST = [
{'ip': '192.168.0.218', 'portbegin': 464, 'portend': 464},
{'ip': '192.168.0.220', 'portbegin': 34684, 'portend': 34685}
]
'''
# 服务器信息
HTTP_SERVER_LIST = []
'''
HTTP_SERVER_LIST = [
'http://192.168.0.236/web/page/',
'http://192.168.0.235:80/web/video/aboutHFS/HFS.txt'
]
'''
# ---------------------------------------------
# 函数实现
# ---------------------------------------------
# 读取配置文件,返回配置文件字符串
'''
{
'clients': [{'ip': '192.168.0.218', 'portbegin': 464, 'portend': 464}, {'ip': '192.168.0.220', 'portbegin': 34684, 'portend': 34685}],
'servers': ['http://192.168.0.236/web/page/', 'http://192.168.0.235:80/web/video/aboutHFS/HFS.txt', 'http://192.168.0.235']
}
'''
def readCfgFile():
try:
with open('config.cfg', 'r') as f:
return f.read() # 返回字符串
except:
print "Error: ReadCfgFile fail!"
return None
# 获取本地业务地址,放入序列svrIps
def getServiceIp(svrIps):
hostname = socket.gethostname()
localIP = socket.gethostbyname(socket.gethostname())
if PRINT_SW:
print "Hostname:"
print " %s" % hostname
print "Local IP:"
print " %s" % localIP
ipList = socket.gethostbyname_ex(socket.gethostname())
if PRINT_SW:
print ipList
for ips in ipList:
# 过滤空序列、主机名
if ips and (not isinstance(ips, str)): # ips是一个序列,其中每个元素是IP地址字符串
'''
if PRINT_SW:
print "External IP:"
'''
for ip in ips:
'''
if PRINT_SW:
print " %s" % ip
'''
svrIps.append(ip)
# 获取客户端列表,eg: HTTP_SERVER_LIST = list(getClientInfo())
def getClientInfo():
cfginfo = eval(readCfgFile())
# 校验配置文件中的IP
# a.首先获取本地业务IP地址
locIps = []
getServiceIp(locIps)
# b.然后对比配置文件中的地址
validDicts = [] # 保存配置文件中的合法元素
for sockdict in cfginfo['clients']:
try:
locIps.index(sockdict['ip'])
except ValueError : # 如果发生异常,说明sockdict中的IP地址不在本PC上,则丢掉
print "Error: " + sockdict['ip'] + " in <config.cfg> is not valid, it will be discarded!!!"
continue
else: # 没有异常,则保存该字典
validDicts.append(sockdict)
if PRINT_SW:
print validDicts
return validDicts
# 获取服务端列表,eg: HTTP_SERVER_LIST = list(getServerInfo())
def getServerInfo():
cfginfo = eval(readCfgFile())
if PRINT_SW:
print cfginfo['servers']
return cfginfo['servers']
# 根据URL获取Server的IP、port、filepath,以字典的形式返回
def getServerSocket(url):
strIp = ""
port = 0
filepath = ""
if 0 != url.find("http://"): # URL必须以“http://”开头(暂时不考虑https的场景)
print "Error: URL is invalid: %s !!!" % url
return
# 首先,去掉“http://”
urlUnhttp = url[7:]
# 然后判断有无“/”
firstXieGnagLoc = urlUnhttp.find("/") # urlUnhttp中第一个“/”下标
firstMaoHaoLoc = urlUnhttp.find(":") # urlUnhttp中第一个“:”下标
if (-1) == firstXieGnagLoc and (-1) == firstMaoHaoLoc: # "192.168.0.235"
strIp = urlUnhttp
port = 80
filepath = "/"
elif (-1) == firstXieGnagLoc and firstMaoHaoLoc > 0: # "192.168.0.235:8988"
strIp = urlUnhttp[:firstMaoHaoLoc]
port = int(urlUnhttp[firstMaoHaoLoc + 1:])
filepath = "/"
elif firstXieGnagLoc > 0 and (-1) == firstMaoHaoLoc: # "192.168.0.235/..."
strIp = urlUnhttp[:firstXieGnagLoc]
port = 80
filepath = urlUnhttp[firstXieGnagLoc:]
elif firstXieGnagLoc > 0 and firstMaoHaoLoc > 0: # "192.168.0.235:8988/..."
strIp = urlUnhttp[:firstMaoHaoLoc] # 这种情况下,默认URL中“:”在“/”左边
port = int(urlUnhttp[firstMaoHaoLoc + 1:firstXieGnagLoc])
filepath = urlUnhttp[firstXieGnagLoc:]
else:
print "Error: URL is unable reslute: %s!!!" % url
svrdict = {}.fromkeys(["ip", "port", "filepath"])
svrdict["ip"] = strIp
svrdict["port"] = port
svrdict["filepath"] = filepath
return svrdict
# 轮询服务器和客户端发起HTTP请求,eg: runHttpCliet(HTTP_CLIENT_LIST, HTTP_SERVER_LIST)
def runHttpCliet(clients=[], servers=[]):
if (None == clients) or (None == servers): # 保护一下
print "Error: clients or servers is None!!!"
return
for urlstr in servers:
svrdict = getServerSocket(urlstr) # 解析URL
print "svrdict =", svrdict
if None == svrdict["ip"] or None == svrdict["port"]:
print "Error: Server is invalid!!!", svrdict
continue # 执行下一个server
for httpClient in clients:
print "httpClient =", httpClient
for clientPort in range(httpClient['portbegin'], httpClient['portend'] + 1):
try:
myHttpConn = httplib.HTTPConnection(svrdict["ip"], svrdict["port"],
timeout = 2, # 设置连接超时等待(单位:s)
source_address = (httpClient["ip"], clientPort))
myHttpConn.debuglevel = 0 # 调试模式开关
if 0 == myHttpConn.debuglevel:
print " ---- Http Request ----"
print " " + httpClient["ip"] + ":", clientPort, \
" --> " + svrdict["ip"], svrdict["port"], ": " + svrdict['filepath']
myHttpConn.request("GET", svrdict['filepath']) # 资源路径以“/”开始
myHttpResp = myHttpConn.getresponse()
if 0 == myHttpConn.debuglevel:
print " ", myHttpResp.status, myHttpResp.reason # 响应码和状态信息
# 此处必须读响应内容,如果不读取,buff将溢出!!!
data1 = myHttpResp.read()
pass
except:
print "Exception!"
continue
finally:
# print data1 # 打印响应内容
print " Http(%s:%s --> %s:%s) will be closed!" % \
(httpClient["ip"], str(clientPort), svrdict["ip"], str(svrdict["port"]))
myHttpConn.close() # 关闭连接
# ---------------------------------------------
# main模块
# ---------------------------------------------
if __name__ == "__main__":
HTTP_CLIENT_LIST = list(getClientInfo()) # 构造客户端
print "HTTP_CLIENT_LIST =", HTTP_CLIENT_LIST
HTTP_SERVER_LIST = getServerInfo() # 构造服务端
print "HTTP_SERVER_LIST =", HTTP_SERVER_LIST
runHttpCliet(HTTP_CLIENT_LIST, HTTP_SERVER_LIST) # 发起请求
2.配置文件
# config.cfg
# clients: {"ip": "客户端的IP地址", "portbegin": 起始端口号, "portend": 结尾端口号}
# servers: 暂时只支持 “http://IP地址”的格式的URL
{
"clients" : [
#{ "ip": "192.168.0.221", "portbegin": 1, "portend": 65535 },
{ "ip": "192.168.0.220", "portbegin": 65333, "portend": 65433 },
],
"servers" : [
"http://192.168.0.235/web/video/aboutHFS/HFS.txt"
]
}