http://czug.org/blog/eishn/python-jishupeixun-disanzhoujiangyi
簡單的網絡通信及即時聊天
? 今天是網絡編程。不妨做一個即時聊天工具吧, 不過這次的程序很簡陋, 只能說是一個網絡對講機罷了。
? 今天我不準備去講更底層的東西, 比如使用 Socket 來編寫通信程序。不過以后, 可能就是下次我們就會涉及到。
? 然而, 今天的東西相當有用。在沒有必要鉆牛角尖的時候 (這是大多數的情況), 今天所用到的方法幾乎是第一選擇。使用 XMLRPC 來進行網絡編程, 確實出奇的簡單。但是請注意, 千萬不要被現在國內的風氣給誤導了, 其實使用簡單的工具來進行編程并不愚蠢, 相反是你聰明的表現。而且, 復雜的應用通常是用最簡單的方法建立的, 如果妄圖使用石器時代的工具來建造高樓大廈, 那幾乎是不可能的。
? 下面先來個服務器。
? from SimpleXMLRPCServer import SimpleXMLRPCServer
? def foo():
??? return "Hello world!"
? server = SimpleXMLRPCServer( ("localhost", 8000) )
? server.register_function(foo)
? server.serve_forever()
? 用 IE 來訪問 http://localhost:8000 看看我們得到了什么? 是一個出錯頁面, 不錯, 這表示我們的服務器工作正常, 只是訪問的方法不對而已。
? 下面, 給出這個程序的客戶機程序。
? from xmlrpclib import ServerProxy
? server = ServerProxy("http://localhost:8000")
? print server.foo()
? 我們會看到服務器返回了 "Hello world!"。這里 localhost 是指本機, 8000 是端口, 我們通常會指定大于 1024 的端口號。localhost 我們通常會用域名 (機器名) 或 IP 來代替, 而端口號是任意的。
? 下面, 該傳些東西了。比如發送一句話到服務器上去顯示出來。
? from SimpleXMLRPCServer import SimpleXMLRPCServer
? def msg(s):
??? print s
??? return True
? server = SimpleXMLRPCServer( ("localhost", 8000) )
? server.register_function(msg)
? server.serve_forever()
? 對應的客戶機程序。
? from xmlrpclib import ServerProxy
? server = ServerProxy("http://localhost:8000")
? while True:
??? msg = raw_input()
??? server.msg(msg)
? 開個玩笑, 一個即時通信工具已經寫好了。兩臺機器互相知道 IP 或者機器名, 協商好端口號。然后打開一個服務器、將客戶機指向對方的服務器就可以了。
? 那么怎么將客戶端和服務器合并在一起呢? 因為調用 serve_forever() 之后程序就停在那里了, 所以無法再接收用戶輸入的東西了。這里順便講一下多線程編程, 但是這個話題不在本次主題之內, 大家僅做理解就可以了。
? import thread
? from SimpleXMLRPCServer import SimpleXMLRPCServer
? from xmlrpclib import ServerProxy
? def msg(s):
??? print s
??? return True
? def run_server():
??? my_server = SimpleXMLRPCServer( ("localhost", 8001) )
??? my_server.register_function(msg)
??? my_server.serve_forever()
? def run_client():
??? your_server = ServerProxy("http://localhost:8002")
??? while True:
????? msg = raw_input()
????? your_server.msg(msg)
? thread.start_new_thread( run_server, () )
? run_client()
? 第二個差不多, 只是把互相的地址換了一下而已。
? import thread
? from SimpleXMLRPCServer import SimpleXMLRPCServer
? from xmlrpclib import ServerProxy
? def msg(s):
??? print s
??? return True
? def run_server():
??? my_server = SimpleXMLRPCServer( ("localhost", 8002) )
??? my_server.register_function(msg)
??? my_server.serve_forever()
? def run_client():
??? your_server = ServerProxy("http://localhost:8001")
??? while True:
????? msg = raw_input()
????? your_server.msg(msg)
? thread.start_new_thread( run_server, () )
? run_client()
? 這樣, 一對對講機就寫好了。
? 接下來就要用到我上一次講到的圖形界面的知識, 用 Tkinter 來寫一個界面了。
? 首先把窗體畫出來。
? from Tkinter import *
? wnd = Tk()
? wnd.lab = Label(wnd, text="---")
? wnd.ent = Entry(wnd)
? wnd.btn = Button(wnd, text="send")
? wnd.lab.pack()
? wnd.ent.pack(side=LEFT)
? wnd.btn.pack(side=LEFT)
? 然后把剛才的網絡部分加上去。
? import thread
? from SimpleXMLRPCServer import SimpleXMLRPCServer
? from xmlrpclib import ServerProxy
? # 第一個對講機
? my_server?? = SimpleXMLRPCServer( ("localhost", 8002) )
? your_server = ServerProxy("http://localhost:8001")
? # 第二個對講機 (需要交換一下地址)
? # my_server?? = SimpleXMLRPCServer( ("localhost", 8001) )
? # your_server = ServerProxy("http://localhost:8002")
? def msg(s):
??? wnd.lab.config(text=s)
??? return True
? def run_server():
??? my_server.register_function(msg)
??? my_server.serve_forever()
? def send():
??? msg = wnd.ent.get()
??? wnd.ent.select_range(0, len(msg))
??? your_server.msg(msg)?
? wnd.btn.config(command=send)
? thread.start_new_thread( run_server, () )
? wnd.mainloop()
? 因為程序比較長, 所以另外一個終端就不寫了。注意, 這里兩臺終端的地址是在程序中寫死的。而且現在的程序只能顯示最近收到的一條消息。
? ·我們可以使用 Tkinter 中的輸入框來叫用戶自己輸入目標機器的地址和端口。
? ·我們可以使用 Tkinter 中的編輯框組件來顯示多行消息。
? 這個作為這次的作業。我的意思是完善這個聊天程序, 做成比較漂亮的樣子。同時思考一下如何來實現一個多人聊天室。
? 下周可能會涉及到 Socket, 請預習一下。