我的P2P聊天程式到目前,已經可以讓互相知道外網IP的兩人互相連結。但對於一般使用者來說,要曉得自己的IP已不容易,還要知道對方的!變成還是得要經由其他聊天軟體先交換IP,使用上不方便。於是接下來P2P程式的目標,就是做出能夠自動依據使用者輸入的聊天室名稱,來配對使用者。
構想是這樣的,A B兩人要聊天,A先打開了程式,設定聊天室名稱為「room」,程式會去訪問網路上紀錄各個聊天室的試算表,去得知聊天室『room』是否存在。當聊天室『room』不存在,A的程式便會以A的電腦作為聊天室『room』的伺服器。再來,B也開啟了程式並連結到『room』,程式一樣到網路上的試算表去尋找『room』,發現已經有人開啟了,再來就會根據在試算表上的IP來連結到A的電腦。
因此,要能夠自動配對,一定要有個穩定的伺服器,並提供存取資料的服務。說到這裡,大家應該都會想到雲端硬碟,沒錯,Google、dropbox等雲端硬碟服務,都有提供API供開發者使用,只要去申請一個項目(多半不用錢),就可以讓程式透過API去控制這些雲端硬碟。舉個例子,如果想要製作一個幫使用者清空雲端硬碟垃圾桶的程式(好沒意義),就去裝Google drive的API,然後申請個專案,就可以使用Google drive的服務。
而我這個程式有個不一樣之處,我的程式並不是存取「使用者」的資料,而是存取我在雲端的一個文件,所以申請專案後,還須辦一個機器人帳號(service account),這樣程式存取的就是這個機器人帳戶的文件,假如我金鑰被盜,頂多也就機器人帳號的資料被存取,我本帳的資料都活得好好的。
1.與Pydrive的苦戰
一開始就想使用Google,畢竟Google的空間大,我平常也都使用這家,所以就去查Google的API。最早的想法是用編輯權限連結,再去模擬網頁操作來存取,但後來發現它有API,當然就直接用API了。
Google API的中文資料不多,所以找的很辛苦,可能是因為像我這樣的獨立開發者很少想碰這種吧!後來只好看他原文教學,但我不知為何從第一步就卡住了,而且冒出了很多奇怪的報錯,後來一度以為是版本問題,所以放棄了Google。
Google沒有我就去找Dropbox,看一些網路上的評論,Dropbox對python是很友善的,所以就去辦了人生第一個Dropbox帳戶,但跟Google一樣,中文教學少之又少,一個下午過去還是什麼都沒有,最後就不了了之了。
2.再次挑戰
自從自動配對失敗之後,點對點聊天程式就慢慢沒做了,改去做了其他的專案,但過了一個月,想到可以用這個作品去參加科展,於是又翻了出來,仍然是卡在自動配對,於是我再度的去研究Google API。
我這個時候才發現Google版本不合是個誤解,耐心的從頭開始做,吃力看原文教學還有文檔,終於弄出了一點成果(成功的登入),但翻了翻文檔,就是找不到操作機器人帳戶的函數。
直到我找到了最關鍵的一篇教學:使用Python上傳資料到Google試算表 – 高中資訊科技概論教師黃建庭的教學網站。
這裡頭的使用的並不是Pydrive,而是更基本的Oauth2還有專門存取google試算表的gspread,oauth2是一種用常用的登入模式,像是玩一個遊戲,要辦帳號時,選擇以facebook帳號登入,就是使用這種協定。
這篇教學的內容跟我的需求幾乎完全重疊,所以我不花多少力氣就完成了登入並存取。
3.模組化
為了方便日後的存取,我製作一個專門用來存取資料的Class,主要功能有搜尋、寫入、移除等,完成了模組後,基本上自動配對已經完成了。
後來因應程式翻新,我重寫了負責網路的文檔,並用class架構包覆,以利未來的開發(之前是指用函數),把網路取得IP的部份跟寫好的模組結合,自動配對就完成了。
4.錯誤
後來又修了許多地方,最後釋出第1測試版時,在學校的電腦測試,發生了奇怪的錯誤。
一開始用隨身碟Linux開,完全無法連線,明明都可以用瀏覽器,但是在命令列操作時就會卡住,點Ctrl C斷開來看,發現都是卡在最初要連線的地方。由於懷疑是系統沒更新,用sudo apt update + upgrade,卻也會卡住。
後來開原來的Windows測試,發現還是不能用,雖然可以連線到Google drive,但是非常~慢,要寫入一個操作,需要五分鐘,這以電腦的標準看,都以經過五天了。詭異的是,好不容易取得了目標IP,連過去卻被「遠端主機強制關閉了一個現存的連線」。發生這樣錯誤的,包括二年級導師室、班上教室,但是電腦教室還有教務處電腦卻可以運行。而且我有一個朋友跟他測試時也發生這樣的錯誤。
經事後分析,估計原因是防火牆的緣故,可能學校教師用電腦有裝比較安全的防火牆,所以我的程式被封鎖了。也有可能是那邊NAT種類不同的原因,不過點對點軟體本來就不可能萬能,因為要克服各式各樣的NAT和防火牆,沒有辦法把每一種都打洞(如果真的可以防火牆業者也要檢討了)。
第一次試用版的commit:https://github.com/lancatlin/P2P-/tree/71331540be8f90ced919416aca523cb9946369f9
後記:
專心於開發,很久沒有更新部落格了,這次講的主題是我苦戰了一個月自動配對,事實上遇到的問題比文章中描述的還多,不過最終還是解決了!!
感謝時常幫助我的兩位網友!
自動配對的模組程式碼:
from oauth2client.service_account import ServiceAccountCredentials as SAC import gspread,key class GetIP: def __init__(self,sheet): k = key.key() k.read() scopes = ['https://spreadsheets.google.com/feeds'] service = SAC.from_json_keyfile_name('key.json',scopes) gc = gspread.authorize(service) k.remove() self.sheet = gc.open(sheet).sheet1 self.all = self.sheet.get_all_records() def search(self,name): all = self.all for i in all: if i['Name'] == name: return {'wan':i['wan'],'lan':i['lan'],'port':i['port']} return None def set_IP(self,name,wan,lan,port): self.sheet.append_row([name,wan,lan,port]) self.all = self.sheet.get_all_records() print(self.all) def clear(self,name): all = self.sheet.get_all_records() all_len = len(all) print(all,all_len,name) for i in range(all_len): if all[i]['Name'] == name: self.sheet.delete_row(i+2) print(i+1) break def get_all(self): return self.sheet.get_all_records() if __name__ == '__main__': test = GetIP('client') print(test.get_all())
留言列表