#
netsh firewall
set opmode mode = ENABLE
Socks5的工作程序
1.客戶端向Socks5服務器發出請求信息。
2.Socks5應答
3.客戶端接到應答后發送向Socks5服務器發送目的服務器的ip和端口
4.Socks5與目的服務器連接
5.Socks5將客戶端發出的信息傳到目的服務器,將目的服務器發出的信息傳到客戶端。代理完成。
由于網上的信息傳輸都是運用tcp或udp進行的,所以使用socks5代理可以辦到網上所能辦到的一切,而且目的服務器不會反查到客戶端的真實ip,既安全又方便 sock5支持UDP和TCP,但兩種代理是有區別的,以下分類說明
如何用代理TCP協議
1.向服務器的1080端口建立tcp連接。
2.向服務器發送 05 01 00 (此為16進制碼,以下同)
3.如果接到 05 00 則是可以代理
4.發送 05 01 00 01 + 目的地址(4字節) + 目的端口(2字節),目的地址和端口都是16進制碼(不是字符串?。。?。
例202.103.190.27 - 7201 則發送的信息為:05 01 00 01 CA 67 BE 1B 1C 21 (CA=202
67=103 BE=190 1B=27 1C21=7201)
5.接受服務器返回的自身地址和端口,連接完成
6.以后操作和直接與目的方進行TCP連接相同。
如何用代理UDP連接
1.向服務器的1080端口建立udp連接
2.向服務器發送 05 01 00
3.如果接到 05 00 則是可以代理
4.發送 05 03 00 01 00 00 00 00 + 本地UDP端口(2字節)
5.服務器返回 05 00 00 01 +服務器地址+端口
6.需要申請方發送 00 00 00 01 +目的地址IP(4字節)+目的端口 +所要發送的信息
7.當有數據報返回時 向需要代理方發出00 00 00 01 +來源地址IP(4字節)+來源端口 +接受的信息
注:此為不需要密碼的代理協議,只是socks5的一部分,完整協議請查看RFC1928
名字很滑稽,使用方法與 pgsql for python使用方式有所不同 ,但都 遵循DB2.0 http://initd.org/psycopg/docs/usage.html 參考文檔
>>> cur.execute("INSERT INTO foo VALUES (%s)", ("bar",)) # correct 注意 %s不能攜帶''字符串定界符;參數tuples必須添加末尾 ,
>>> cur.execute( ... """INSERT INTO some_table (an_int, a_date, a_string) ... VALUES (%s, %s, %s);""", ... (10, datetime.date(2005, 11, 18), "O'Reilly")) 參數數組傳遞方式
>>> cur.execute( ... """INSERT INTO some_table (an_int, a_date, another_date, a_string) ... VALUES (%(int)s, %(date)s, %(date)s, %(str)s);""", ... {'int': 10, 'str': "O'Reilly", 'date': datetime.date(2005, 11, 18)}) 參數哈希傳遞方式
cur.execute('insert into table_a values(%s)',(psycopg2.Binary(file.read()),)) 插入二進制數據
TileCache默認是Disk緩存Tile數據,存儲和檢索的效率遠不及數據庫,所以要開發數據庫Cache,讀完TileCache代碼,發現其系統結構設計的還算可以 tilecache-2.10\TileCache\Caches目錄下就是TileCache自帶的Cache類型,Cache有個抽象基類,我的數據Cache只要實現這些Cache的接口便能完成到數據庫的Tile存取。
1 class Cache (object): 2 def __init__ (self, timeout = 30.0, stale_interval = 300.0, readonly = False, **kwargs): 3 self.stale = float(stale_interval) 4 self.timeout = float(timeout) 5 self.readonly = readonly 6 7 def lock (self, tile, blocking = True): 8 start_time = time.time() 9 result = self.attemptLock(tile) 10 if result: 11 return True 12 elif not blocking: 13 return False 14 while result is not True: 15 if time.time() - start_time > self.timeout: 16 raise Exception("You appear to have a stuck lock. You may wish to remove the lock named:\n%s" % self.getLockName(tile)) 17 time.sleep(0.25) 18 result = self.attemptLock(tile) 19 return True 20 21 def getLockName (self, tile): 22 return self.getKey(tile) + ".lck" 23 24 def getKey (self, tile): 25 raise NotImplementedError() 26 27 def attemptLock (self, tile): 28 raise NotImplementedError() 29 30 def unlock (self, tile): 31 raise NotImplementedError() 32 33 def get (self, tile): 34 raise NotImplementedError() 35 36 def set (self, tile, data): 37 raise NotImplementedError() 38 39 def delete(self, tile): 40 raise NotImplementedError()
接口夠簡單了吧 ,最主要的實現的 是get,set,getKey這3個主要接口 tilecache.cfg的Cache.type設置為DB_POSTGRES
考慮將shp格式的地圖數據發布到webgis上去的想法有一段時間了,正好有空閑時間便忙碌開來,沒想到期間遇到了諸多的問題
1.開發工具: Geoserver,Openlayer,Ext-js,Postgres/Postgis,Python2.6,PIL,TileCache 2.地圖數據 我的地圖數據是08年的全國地圖,按每個省市分隔開來,每個省市又分了若干個圖層文件,格式是mapinfo的Tab,容量10G 由于沒有全國大比例圖,在偶然的一個機會從網上下載到一份C/S的監控系統,沒想到安裝目錄內就有一份全國圖,就是比例不高。 3.處理過程 1.Tab轉換成shp: Ogr工具可以完成這兩種格式的轉換,編寫python腳本可以輕易處理完 在轉換數據之前需要提醒的是,發現在處理多邊形圖層時,這個多邊形圖層并不是簡單的多邊形,也就是那種mapinfo允許存在polygon和pline的圖層,這將導致之后的導入空間數據庫的失敗,因為postgis要求每個圖層數據類型必須是一致的,不能存在多種類型,所以編寫mapbasic腳本,將這些pline對象從這多邊形圖層中剔去即可。 2.數據校驗: 這個過程非常重要,任何提供的的矢量數據都有可能存在錯誤數據,所以第一步必須要修復這些可能存在的錯誤,工具就是ArcGis,使用其工具對每個省市的每個圖層文件進行修復。 3.導入空間數據庫: 編寫腳本,將shp數據轉成sql文件,此時必須注意空間數據庫的字符編碼與sql數據字符編碼要吻合或者能夠自動轉換。pg2sq由于轉換成sql時,由于shp數據中某些圖層表存儲的字符編碼不統一導致產生的非法的sql數據,所以必須對這些數據進行修正,并采用ultraedit將數據進行轉碼成數據的字符集類型,我使用的是utf-8. 4.數據分離: 由于提供的全國地理數據是沒有根據應用來分層的,所有的道路都合在同一個叫road的圖層內,然后通過屬性來區分道路的級別,由于我們在控制顯示道路時是需要分層分級別的,所以必須將這些數據要分離成不同的道路圖層,道路共10級別(0-9),編寫腳本將每個省市的道路切割成road_?10級道路層(select into即可搞定)。 同樣,除了道路之外還有其他的比如河流,POI對象等都需要進行分割到不同圖層以便更精確的現實控制。 5.配置Geoserver: 數據都有了,接下來就是配置繪制引擎了。Geoserver提供WFS,WMS服務,性能一般,由于是java開發的。不管3721,配置了最新的I5主機,將java虛擬機的內存設置的最大,將postgis的數據庫內存也足夠調大。手工添加了1,2個圖層到geoserver,preview一下,ok! 接下來編寫控制這些圖層的SLD了,這些花了好些時間學習和開發(學習sld對我以前開發嵌入式地圖引擎風格配置也是一種幫助,之后的嵌入式地圖引擎也全部使用sld進行配置了!) 由于全國數據分31個省市,每個省市都配置了21個圖層,所以要人工11加到geoserver還真是很大的問題,不過沒關系,有python在手,然后對geoserver的配置文件研究了一把便寫了腳本將幾百個圖層全加了進去,然后將這些圖層按省市進行分組,再次Preview,ok! 6.Cache Tile生成: 使用過GeoWebCache,發現很多地方實在不好理解,幸好找到了TileCache,代碼也容易修改,研讀了TileCache代碼之后修改了N處地方,把效率提高了10倍以上。現在的問題在于Tilecache實現了Disk Cache,Memory Cache,但就是沒有DB cache,每個tile將創建一個文件,如果這些文件很小,有的甚至才幾十字節也要浪費一個文件塊空間,效率不高,如果采用db的話空間就能節省很多,等以后有了時間自己編寫一個后端為postgres的Tile Cache吧。
Tile Cache生成有些問題要注意: 1. 空白tile: 由于我設置的繪制設置的BBox非常大,所以在繪制的時候有些空白區域也將提交給geoserver進行處理,這樣浪費了處理時間,同時這些產生的小規格圖塊大大占據了磁盤空間,所以修改的代碼將不存儲這些空白tile,僅僅存儲這些tile的文件名稱,而不保存內容 2. tilecache的Resolutions,ZoomLevels,BBox和Openlayers的屬性必須一樣,否則Opnelayers無法顯示正確的tile 3. tile相交檢測: 同樣是空白區域的繪制,如果每次都提交給geoserver的話,geoserver將根據配置的layer去相交并繪制一次,這就完全沒有必要的,我的解決方式就是提前將31個省市產生他們的MBR,然后再tile進行提交給geoserver之前,將請求的tile的bbox與這些省市的mbr進行相交測試,只有相交的圖層才送入geoserver繪制 4. 大網格繪制: 每次以256×256的規格給geoserver繪制全國圖的話效率實在太低,之后修改成2048×2048規格,整體的繪制效率上升了n倍,繪制完了之后采用split_tile.py將這些大塊切割成256規格的小塊,必須注意產生的序號
寫得好累
一下處理過程需要在python2.5與2.6之間切換
Pgsql8.3.5
postgis1.5
tilecache 2.10
geoserver2.0
openlayers
ext-js
django
1.
openlayer顯示地圖無法顯示正確的比例尺
在訪問地圖時設置地圖顯示單位必須為 units:'degrees'
2. 圖層文字標注出現亂碼和重復繪制多個相同名稱
Sld設置的group=true似乎沒有起作用
layer = new OpenLayers.Layer.WMS( "FirstMap","http://localhost:8080/geoserver/wms",{},{singleTile: true, ratio: 1})
必須設置紅色部分的參數,能保證文字不被重復顯示
但是在使用tilecache.py預緩沖圖塊時("http://localhost:9000/tilecache/tilecache.py"),添加了以上紅色參數之后導致無法顯示地圖。
SingleTile:true 參數是作為geoserver的附加屬性由openlayer傳遞到服務器,
所以考慮將此參數通過tilecache.cfg傳遞到geoserver是否能夠起到相同效果?
發現使用了signleTile之后,openlayers將不進行塊的緩沖,而是每次請求都到geoserver上去獲取,抓包發現singleTile開啟的話,請求時將不傳遞width/height參數,直接請求bbox大小的地理區域,每次移動地圖將重新加載整個區域,效率低下;
但是關閉singleTile的話,依次連續請求多個網格塊,默認是256x256,導致有些圖層比如背景層1024×1024的話將請求4x4個網格塊,每個塊都將繪制背景的文本標識,因為這些塊是離散繪制的所以顯示在地圖上的話將是重復的文本顯示出來了,所以避免這個問題只有如下解決:
1.
放大網格的大小規格,使一定的地理范圍盡可能的處在一個網格內被繪制
目前這種方式似乎是最佳方式,tilecache 默認tile規格是256*256,在繪制全國圖的時候設置1024*1024方式去請求geoserver,然后使用split_tile.py切割土塊即可。
2.
控制這些層的顯示屬性,限制只有在某些比例尺時被顯示
3.
手工編輯地圖數據,合并多邊形對象,這樣就可以防止重復繪制多邊形的名稱標注,導致一個省份名稱繪制多次
Tilecache為了支持apache訪問,必須安裝到python/lib/目錄下,并且tilecache.cfg也在這個安裝目錄下。
Tilecache.cfg修改之后必須重新啟動apache服務
如果geoserver實時繪制的話允許同時傳遞多個層名稱給geoserver進行繪制
new
OpenLayers.Layer.WMS( "FirstMap",
"http://localhost:8080/geoserver/wms",
{ layers:’shanghai,china,…’})
如果tilecahce加載tile網格塊的話,layers屬性不能傳遞多個圖層,因為多個圖層就是返回多個tile塊,只有在tilecache.cfg中配置多個layer名稱
[east_china]
type=WMSLayer
url=http://localhost:8080/geoserver/wms
layers=shanghai,jiangshu,zejiang
extension=png
resolutions=0.17578125,0.087890625,0.0439453125,0.02197265625,0.010986328125,0.0054931640625,0.00274658203125,0.00137329101,0.0006,0.0003,0.00015,0.000075,0.000035,0.000018,0.000009,0.0000045
bbox=70,10,130,60
優化批量自動化繪制地圖
1.
tilecache_seed.py提交layers給geoserver 時,如果提交全國所有layers,geoserver將處理每個layer,即使layer與當前可見地理區域不想交,但還是會被循環處理;所以必須改寫tilecahe_seed.py程序,檢測只有相交的圖層傳送給geoserver渲染。
改寫部分在TileCache/Layers/WMS.py中,
def
renderTile(self, tile):
wms = WMSClient.WMS( self.url, {
"bbox": tile.bbox(),
"width": tile.size()[0],
"height": tile.size()[1],
"srs": self.srs,
"format": self.mime_type,
"layers": self.layers,
}, self.user, self.password)
tile.data, response = wms.fetch()
return tile.data
self.layers參數就是tilecache.cfg中參數layers定義的層列表,所以只需要修改這個參數即可。
處理方式:
將tile.bbox()的地理區間與數據庫中的省市層最大mbr進行相交測試,只有相交的才提交給geoserver進行處理。
修改之后
測試:
將網格規格調整為256*256,繪制east_china圖層第7顯示級別,花銷48秒
修改代碼如下:
def
isIntersect(self,rc1,rc2):
if rc1[2] < rc2[0] or rc1[3] < rc2[1]
or rc1[0] > rc2[2] or rc1[1] > rc2[3]:
return False
return True
def renderTile(self, tile):
import sys,string
sys.path.append('c:/')
import cities_mbr
layers = self.layers.split(',')
newLayers=[]
for layer in layers:
rc = cities_mbr.G_CITIES_MBR[layer]
rc2 = tile.bbox().split(',')
rc2 = map(float,rc2)
if self.isIntersect(rc,rc2):
newLayers.append(layer)
layers = string.join(map(str,newLayers),',')
if len(newLayers) == 0: #no any
insercted layer
layers='china:china_blank_layer' #here i select shanghai as empty city to
fill
print layers
wms = WMSClient.WMS( self.url, {
"bbox": tile.bbox(),
"width": tile.size()[0],
"height": tile.size()[1],
"srs": self.srs,
"format": self.mime_type,
#"layers": self.layers,
"layers": layers,
}, self.user, self.password)
print 'x*'*20
print self.url,tile.bbox(),layers
#import sys
#sys.exit(0);
tile.data, response = wms.fetch()
return tile.data
注意以上紅色代碼,當檢索不能匹配任何圖層時,需要geoserver返回空白圖塊,self.layers必須設置一個數據庫中可用的圖層名稱,這個圖層只是為了繪制空白塊的,所以可以在postgis中創建一個point層即可或者一個空層,然后添加一個遠離中國地理區域的一個點即可.
2.
顯示比例越小的時候,繪制地圖需要更多的時間,那是由于顯示的越大繪制的圖層就越多。
要使多臺機器同時分工繪制地圖的話,
可以按層進行分割處理和劃分經緯度的方式進行。前者適用與高比例尺的顯示,后者就是小比例尺的顯示。
小顯示比例時,tilecache將圖層進行網格化處理,由西至東,由下至上。所以提交給處理機器以不同的bbox即可,處理完成之后再將這些圖塊重新進行編號即可。()
3.
在低縮放比的情況下放大tile的規格,默認是256×256,將其設置為256×n大小,這樣可以提高每次請求的效率,之后再將圖塊切割為256×256大小的png圖塊。 這就要求geoserver的sld關閉
<vendor-group>true</vendor-group>開關
測試:
將網格規格調整為1024*1024,繪制east_china圖層第7顯示級別,花銷30秒
將網格規格調整為256*256,繪制east_china圖層第7顯示級別,花銷200秒
圖像擴大了16倍,時間縮短了6倍
大圖塊產生之后切割為小圖塊,需要重新索引文件編號。
設A規格圖塊和B規格圖塊(A*4=B),如果A繪制需要產生400列(0-399),400行(0-399),那B只需要產生100列100行。
Tilecache預處理數據存儲方式:
圖塊數據繪制時按照經度從西到東,維度從南到北的順序依次繪制出網格圖塊。
每一列的圖塊都創建出一個目錄,從下標0開始。
繪制方式:
For(x=0;x<columns;x++){
For(y=0;y<rows;y++){
Draw_tile()
}
}
層名稱/縮放級別/000/000/列編號/000/000/行圖塊文件.png
Tilecache的數據存儲目錄在刪除時必須注意停止apache服務
Apache提供tile服務時將自動使用python2.6下的tilecache代碼
操作數據庫是采用的是pgpostgresql,目前只支持python2.5,所以必須先注視掉c:/python2.6, 打開c:/python2.5
在實際的cache生成過程中遇到大地理范圍和多顯示比例的問題時,生成tile cache的耗時是個頭大的問題,越低比例尺的繪制耗時將成幾何倍數上升,如果要繪制1:1000的全國圖的話,完成工作一臺主機可能需要幾個月的時間,tilecache默認的請求tile規格是256×256,性能實在太低,所以提高每次向geoserver請求圖塊的規格來稍微提高速度,目前我采用2048×2048。 但openlayers里面256×256是最佳的cache規格,所以tilecache產生的tile必須進行切割成256規格
1 # -*- coding:utf-8 -*- 2 3 #切割大地圖塊到小圖塊,重新索引圖塊文件目錄 4 5 #層名稱/縮放級別/000/000/列編號/000/000/行圖塊文件.png 6 7 import sys, traceback,threading,time,struct,os,os.path,shutil,distutils.dir_util,array,base64,zlib 8 import PIL,Image 9 10 g_layerName='east_china' 11 12 srcTiles={'path':'','size':(1024,1024)} 13 destTiles={'path':'','size':(256,256)} 14 15 #layerName - 處理的地圖層名,在tilecache.cfg中定義 16 #scale - 顯示級別 17 #tileDir - 圖塊存儲目錄 18 #destDir - 切割圖塊存儲目錄 19 #tilesizeFrom - 當前圖塊規格 20 #tilesizeTo - 目標圖塊規格 21 #注意: 維度從下至上遞增 22 #一個大網格塊列切割成多列,行且歌城多行 23 def splitTile(layerName,scale,tilesDir,destDir,tilesizeFrom=(1024,1024),tilesizeTo=(256,256)): 24 xcols = tilesizeFrom[0]/tilesizeTo[0] 25 xrows = tilesizeFrom[1]/tilesizeTo[1] 26 27 path2 = "%s/%s/%02d/000/000"%(destDir,layerName,scale) 28 if not os.path.exists(path2): 29 os.makedirs(path2) 30 path1 = "%s/%s/%02d/000/000"%(tilesDir,layerName,scale) 31 cols = map(int,os.listdir(path1)) 32 for col in cols: #1列要切割成n列 33 path1 = "%s/%s/%02d/000/000/%02d/000/000"%(tilesDir,layerName,scale,col) 34 for x in range(xcols): 35 newcol = col*xcols + x 36 path2 = "%s/%s/%02d/000/000/%02d/000/000"%(destDir,layerName,scale,newcol) #大土快可以切割成多列 37 if not os.path.exists(path2): 38 os.makedirs(path2) 39 #print path1 40 files = os.listdir(path1) #list columns 41 for file in files: 42 name,ext = file.split('.') 43 path3 = "%s/%s/%02d/000/000/%02d/000/000/%s"%(tilesDir,layerName,scale,col,file) # 44 img = Image.open(path3) 45 46 rows = range(xrows) 47 rows.reverse() 48 for y in rows: 49 box = (x*tilesizeTo[0],y*tilesizeTo[1],(x+1)*tilesizeTo[0],(y+1)*tilesizeTo[1]) 50 #print box 51 newimg = img.crop(box) 52 y = int(name)*xrows + xrows - y -1 53 print x,y 54 path2 = "%s/%s/%02d/000/000/%02d/000/000/%02d.png"%(destDir,layerName,scale,newcol,y) #注意產生的文件編號的數值寬度 55 newimg.save(path2) 56 57 def test(*a,**b): 58 print len(a),b 59 #test(1,2,3,k=100) 60 61 if __name__=='__main__': 62 splitTile('layer1',1,'E:/NewGis/trunk/python/tile1','E:/NewGis/trunk/python/tile2',(512,512),(32,32))
1 # -*- coding:utf-8 -*- 2 3 #計算的網格數量 4 5 import sys, traceback,threading,time,struct,os,os.path,shutil,distutils.dir_util,array,base64,zlib 6 7 DPI= 90.0 #每英寸的像素數量 8 METRER_PER_INCH = 2.54 /100.0 #每英寸多少米 9 PIXEL_WIDTH = METRER_PER_INCH / DPI #每個象素多少米 10 11 METERS_PER_DEGREE = 1862 * 60 12 13 SCALE = 100000 #縮放比 14 15 GEO_RECT = (70,10,134,60) 16 17 w = (GEO_RECT[2]-GEO_RECT[0]) * METERS_PER_DEGREE 18 h = (GEO_RECT[3]-GEO_RECT[1]) * METERS_PER_DEGREE 19 20 TILE_WIDTH = 1024*4 #圖塊規格 21 TILE_HEIGHT = TILE_WIDTH 22 RENDER_TILE_TIME = 1 23 24 25 ynum = h / (TILE_HEIGHT*PIXEL_WIDTH*SCALE) # SCALE 縮放比例下tile規格的數量 26 xnum = w /(TILE_WIDTH*PIXEL_WIDTH*SCALE) # tile的列數量 27 print "scale:%s,tiles(%s,%s)"%(SCALE,int(xnum),int(ynum)) 28 print u"總圖塊數量:",xnum*ynum,u"消耗時長",xnum*ynum*RENDER_TILE_TIME/3600.0,u"小時(每圖塊耗時%s秒)"%RENDER_TILE_TIME 29 30 #----------------------------------------- 31 RESOLUTION = 0.000018 #顯示精度 每像素多少度 32 #RESOLUTION = 0.0003 #顯示精度 每像素多少度 33 SCALE = RESOLUTION * METERS_PER_DEGREE / PIXEL_WIDTH #計算顯示比例 34 ynum = h / (TILE_HEIGHT*PIXEL_WIDTH*SCALE) # SCALE 縮放比例下tile規格的數量 35 xnum = w /(TILE_WIDTH*PIXEL_WIDTH*SCALE) # tile的列數量 36 ynum = int(ynum) 37 xnum = int(xnum) 38 print xnum,ynum, TILE_WIDTH*PIXEL_WIDTH*SCALE 39 print str(RESOLUTION),"scale:%s,tiles(%s,%s)"%(SCALE,int(xnum),int(ynum)) 40 41 print u"總圖塊數量:",xnum*ynum,u"消耗時長",xnum*ynum*RENDER_TILE_TIME/3600.0,u"小時(每圖塊耗時%s秒)"%RENDER_TILE_TIME 42
估計不是這次的事情,再過4,5年也不一定會去東北,而且是行色匆匆 昨天與老陳約好去ying信調測酒店代理度服務器的事情,老陳就是老陳,擺弄了幾下就在一臺linux主機上配置完了iptables,來不及跟這一幫子人過多的調侃閑聊了,老姐又激動的幾乎暈過去,告知園園現在到了哈爾濱。 馬上與老陳告別,交代了一下httpproxy代碼的安裝和運行便開車去見老姐,帶其到三林之后取了1w塊現金便開車直接去了浦東機場 3點半的飛機,1900塊的價格讓我乍舌了一下,沒有打折的,沒法子了 說實在的,提到飛機是有點發怵的,以前就做過3,4次,每次都跟自己說以后再也不坐飛機了,大概是怕死,死了很多都白費了 飛了近3小時到達哈爾濱,下飛機趕緊找個廁所尿了一下,知道園已經在火車站附近的派出所已呆了白天了,比較著急,打了車便走,東北人也不地道,被宰了7,80塊 終于到了哈爾濱火車站,看到了牌子以及下面的大鬧鐘,還真的是哈爾濱,沿途看到了東北的殺豬菜xx飯店之類的東北特色的名詞。 -12度,其實除了臉凍的發紫之外人整個都算還好,不是太冷,就是剛下過大雪所以地很滑。 東北確實破破爛爛的,最有特色的就是地上能很明顯看出行人吐的痰,一顆一顆的,星羅棋布,因為氣溫低所以馬上結凍了,似乎細菌也被困所在了里面,所以顯得城市都很干凈。 一路找啊找,沒找到,又打了2,3個電話給園,東北人這個講話的口音還真是有問題,含含糊糊的,一路打聽到了那個站前車站派出所 推門進去,眼睛被迷糊了,里面都很人,所以人說東北外冷內熱呢 園就在那里,看到我笑了笑,我也嚴肅很多,趕忙跟警察打招呼,表示感謝啊,一位馬警官給園買了吃的,我是非常的感激萬分道謝,辦完手續之后便帶園出來吃了李先生,花了41塊錢。 出
來我問園是否要買點啥,帶她去小店買點啥,想來想去還是買了條200的煙,出來找了路上一個小旅店拉客的小妹妹,塞了10塊錢讓她幫著把煙替我送給那個民
警,看她跑進去了我便跟園走了,沒想到沒過一會兒那小妹妹追了我好長一段,告訴我送到了,讓我放心,我拍了拍她一下肩膀,謝謝!東北人真好 一路找
住宿的地方,一時間看花了眼,正好碰上一位旅店拉客的東北大姐,高個子,長得還不錯,應該長我4,5歲的樣子,本想著等一下去火車站買張晚上的車票趁著功
夫找家落腳的地方歇息一下便跟著大姐穿走在火車站附近街道,到了才發現是公房改建的小旅店,野路子旅店,看看這位大姐的熱情程度,算了就不打擊她了,暫時
付了30算到晚上12點之前的費用。 園除了校服之外里面就直接是短褲和短袖T shirt了,真是胖子不怕挨凍,也是自作自受。 跟旅店大姐聊了一番,她從家翻出見滑雪服以50塊賣給了我,給這個園胖子穿上才好受了許多。還是挺劃算的,對這個東北大姐也多了一絲好感,畢竟東北人還是比較豪爽。 之
后我想去火車站,想想單獨留下園在這里也是不放心,便鎖了門帶上她一同出門?;疖囌救丝墒钦娑啵胭I直達上海的車票還真是不簡單,找半天來售票處都沒找
到,想想還是算了,打了了114查詢買明日的飛機票,電話里我頂了2張牌票子,5折,算下來1000一張,那還好,搞定了準備帶園回去,一路上看看哈爾濱
的夜景,別的沒注意啥,就看到哈爾濱最出名的就是哈爾濱紅腸,哈哈,想著回去買一些。 晚上園胖子便呼呼大睡起來,我也死活睡不過去,生物鐘還沒到呢。晚上請了個假,也被楊新笑話了一番。 早上8點半賣票處便電話過來與我確定送票地點,發現她們漏定了1張,我便告知還有個14歲的兒童,事情麻煩了,沒法買票了,也打亂我今天原本的計劃了。 之后便電話給機場公安,機場安檢咨詢辦理手續,其告知必須出具戶口本或者戶籍信息包括照片。想想昨天那煙送的還真是該,多做好事沒錯吧! 園
胖子呼呼大睡,我便馬上起來又來到了站前治安大隊,一個叫宮克的警察很吊,從我見他到離開,他一直在玩他的手機,不知是不是在看色情信息這么投入,東北人
嘛講話就是這么含糊,我反映了情況之后希望他們能開具相關證明,還算可以他們愿意幫忙,也許是昨天煙的緣故,也許確實他們比較通事理,都是幾個50開外的
老警察,總的還都算不錯。最后是一位叫 陳正欽
的警官替我查了公安網內的關于園的戶籍信息,單就是沒有照片,這個咋辦呢,一陣的范暈,一個勁的求再查查其他系統,都沒有全的信息,機場公安又強調必須要
有照片。 在陳警官的指導下,讓我去附近的松花江派出所查詢小孩的戶籍信息,因為我知道園拍過社保卡,有照片信息存儲的,所以便出來一路找到了派出所。 到
了這里,這里的民警一副很強橫的態度,要不是老子求他們辦事才不會裝得低三下四,哀求了多次,又找這里的領導,被直接一口拒絕,說是只對轄區人口負責,其
他的他們沒有這個能力,簡直是畜生,還是人民警察呢,就是這么為全國人民服務的啊,媽的!去了2次,求了n次,只好沒法,折回去的路上又給機場安檢尋求幫
助,安檢讓我拍照然后讓公安蓋章也行,想想那幫松花江的混蛋警察那里也不去了,直接去站前派出所找到陳警官咨詢,被告知可以,便開心了起來,道謝了一下,
趕緊跑回小旅店把園叫起來,喂了點吃的給她,路上刻意留心過附近的照相館,所以拖著園一路小跑到了照相館,拍照,20元。 拿著照片再去站前派出所,陳警官外出了,等了20分鐘,他還是那么熱情,順利的辦完了證明,我可是千恩萬謝,要沒有這個證明估計做火車要2天之后了。 出了大門,再去李先生吃飯,點了幾個菜,吃了60多,席間我跟服務員要調羹,居然東北小妹沒聽懂,惹得旁桌的客人都笑了。出來讓園胖子背對火車站給她留了個點,呵呵! 看看時間10點半了,趕緊打車到民航大廈,11點的大巴一個小時到了太平機場,路上大雪蓋地,這個鬼地方還是人口稀少,都是莊稼地,現在的東北農民估計只好在家玩玩骰子了吧,整個大地都被凍起來了,一個勁的把這些村莊景象往鄉村愛情里的場景套。 到了機場買機票,出具了園的證明,還一直擔心著有啥問題呢,給了錢拿了票,一下子放心了。在侯機的時候才想起東北香腸,這個機場還真是黑的厲害,2斤賣了80塊,想想算了,好歹也是來一次,也算給東北人民捐助了。 飛機延誤了1小時2點30正式開飛。 東北常年陽光明媚,所以干燥。到上海已經5點30了,下著密雨,出了航站,找到自己的車,出庫,交停車費,100,真是吃人,也沒辦法,開上radio,一路跟園時不時的聊上一兩句,顛簸著回家,把園交到了姐手里。
緣于要做個http代理服務器的需求,開始琢磨SocketServer類,看看其有多優秀 BaseServer: 定義基礎服務器接口,這些功能接口提供給子類繼承。同時提供服務處理的骨架 serve_forever() 循環調用 handle_request() handle_request() 調用子類的get_request() ,在tcpServer時實則進行accept()應答; 驗證處理 verify_request(); 最終處理請求 process_request(), verify_request() 虛函數 process_request() 虛函數,這個函數并沒有直接在BaseServer的子類TcpServer中被重載,而是在TcpServer的派生類中通過另一個父類來實 現,比如 ThreadingTCPServer的基類ThreadingMixIn.process_request()實現了此功能函數 finish_request(request, client_address) 執行一次完整的socket數據讀入處理,如果是ThreadMixInTcpServer產生的request,這個方法內必須實行循環讀取socket數據,直到socket關閉。(此處 request 就是 socket對象)
def finish_request(self, request, client_address): """Finish one request by instantiating RequestHandlerClass.""" self.RequestHandlerClass(request, client_address, self)
在finish_request里面便將讀取socket數據的任務扔給了RequestHandler去處理了,代碼可以跳過去看了 ##--------------------------------------------- TcpServer: tcp服務器 __init__(self, server_address, RequestHandlerClass) 需要提供服務偵聽地址和請求處理類對象 server_bind() 綁定服務器地址 server_activate() 激活服務器 server_close() 關閉服務器 fileno() 返回服務器socket的句柄fd編號 get_request() 接收應答accept() close_request(request) 關閉socket,request即為socket對象 三種輸出處理方式: 阻塞方式、線程處理(ThreadingMixIn)、進程處理(ForkingMixIn) ThreadingMixIn: 線程模型 process_request( request, client_address) 為請求的鏈接創建新的線程,在創建線程時直接指定線程入口和參數:
import threading t = threading.Thread(target = self.process_request_thread, args = (request, client_address)) if self.daemon_threads: t.setDaemon (1)
process_request_thread() 線程處理socket入口,負責接收數據,代碼實現有點繞,看看代碼
def process_request_thread(self, request, client_address): try: self.finish_request(request, client_address) self.close_request(request) except: self.handle_error(request, client_address) self.close_request(request)
ThreadingMixIn 其實就是線程代理,還是調用finish_request()進入處理tcp數據的循環,處理完成便close_request()。但是finish_request和close_request并未在ThreadingMinxIn內定義,在哪里呢? 通過研讀ThreadingTcpServer,原來通過ThreadingTcpServer這個finish_request又跑回了BaseServer.finish_request() ThreadingTCPServer(ThreadingMixIn, TCPServer) 裝配成線程池處理的tcp服務器 BaseRequestHandler: 請求處理基礎對象,提供統一的行為接口實現處理socket數據。 BaseRequestHandler比較好玩,在構造函數內完成了所有的操作,見代碼:
def __init__(self, request, client_address, server): self.request = request self.client_address = client_address self.server = server try: self.setup() self.handle() self.finish() finally: sys.exc_traceback = None # Help garbage collection
setup()對應的子類會進行初始化處理 self.handle() 直接調用子類的處理函數,可以參考 BaseHTTPRequestHandler(SocketServer.StreamRequestHandler)::handle() StreamRequestHandler(BaseRequestHandler) 流式socket處理類 setup() 設置好socket對象和讀寫文件句柄 rfile/wfile HTTPServer(SocketServer.TCPServer) http服務器 BaseHTTPRequestHandler(SocketServer.StreamRequestHandler) 流式的請求處理類 handle() 處理入口,在基類BaseRequestHandle()的構造函數中直接調用 handle_one_request() 如果不是處理一次則返回false。接收一次socket數據,解析parse_request(),調用對應的do_xxx事件 python 的daemon線程: 如果一個進程的主線程運行完畢而子線程還在執行的話,那么進程就不會退出,直到所有子線程結束為止,如何讓主線程結束的時候其他子線程也乖乖的跟老大撤退呢?那就要把那些不聽話的人設置為聽話的小弟,使用線程對象的setDaemon()方法,參數為bool型。True的話就代表你要聽話,我老大(主線程)扯呼,你也要跟著撤,不能拖后腿。如果是False的話就不用那么聽話了,老大允許你們將在外軍命有所不受的。需要注意的是setDaemon()方法必須在線程對象沒有調用start()方法之前調用,否則沒效果。
|