[Python] ServerSocket
最後這篇來講server socket在python上最後一個也是最方便的module
Python SocketServer: http://docs.python.org/2/library/socketserver.html
官網算是有一些範例, 而且網路上也有一隻影片有簡易教學
youtube 英文教學: http://www.youtube.com/watch?v=OU7AWyw8MfI
基本上SocketServer是大幅簡化了我們要寫Socket Server的module,
他基本支援四種server classes TCPServer, UDPServer, UnixStreamServer, UnixDatagramServer
前兩種很常見, 而後兩種是純Linux使用, 差在一個起始是AF_INET還是AF_UNIX
而SocketServer module如果在預設的情況下是同步的設定, 也就是一個服務處理一個connection
那如果你有多個需求或者講非同步的處理, 可能有的在處理連線有的在處理其他工作, 就可以使用ThreadingMixIn or ForkingMixIn 來幫你解決這類問題
所以要建立一個SocketServer, 有幾個必要步驟
1. 因為既然要寫SocketServer, 就會有相對應的服務要處理, 所以要先建立一個request handler去繼承RequestHandler (這個有幾種種類), 用來實作你要怎麼處理進入的要求
2. 當然你也要有建立一個上述所說的socket class, 並且附上剛剛建立的request handler
3. 有了前面兩個設定之後, 就可以呼叫andle_request() or serve_forever()來幫你開始SocketServer的服務
看起來內容很多而且不小心寫的太像翻譯, 用一點例子輔助說明, 第一個範例我拿官網的解釋
我拿掉註解, 首先這程式很小, 而且照剛剛三步驟就真的寫完了
1. 有一個MyTCPHandler去繼承BaseRequestHandler(有其他更好用的後續提), 然後實作handler要做甚麼就可以, 這邊很單純, 他收client端傳過訊息, 印出傳過來的訊息之後, 再把這訊息變大寫傳出去, 而且用sendall, 所以所有有連線的client都會收到此訊息大寫版
2. 建立SocketServer.TCPServer((HOST, PORT), MyTCPHandler), 這件事情會建立socket也會將剛剛的request handler傳入
3. 呼叫serve_forever, 程式就開始跑了 (想成之前範例的while True)
幾個東西稍微說明一下
self.client_address就是client的位址, 跟當初的accpet()回傳的結果是一樣的
self.request其實就是當初用socket建立出來的socket物件, 所以也可以用self.request.getpeername()去取得client位址, 跟上述一樣
超簡單的範例, 不過, 因為太簡單, 有很多事情還不太方便, 例如說, 我想要避免之前因為中斷結果又會造成connection問題, 或者是需要threading, 所以下面再提供一個稍微小複雜的範例
這範例一樣很笨, 只是在server紀錄一下誰連過來, 然後跟他問聲好XD
不過我額外連Server端都重新繼承了, 除了繼承了ThreadingMixIn之外, 我設定了兩件事情
1. daemon_thread = True, 也就是當main thread死, 其餘thread都跟著死, 不設定開的話, 如果用ctrl+C去中止程式是中止不了的, 以server來講, server thread都中止了, 剩下的理應也沒有理由活著了 (要死一起死!!)
2. allow_reuse_address = True, 你看多貼心, 這次讓你可以設定是不是要reuse address
那我有在main那邊簡單做個try~except, 只是要抓ctrl+C的命令, 有的話就程式結束
而在Handler那端, 拿前幾篇的範例使用, 不過多做了一些訊息log, 像這邊有一個threading.current_thread
這個會取得在這時候運作的thread基本資訊, 例如名稱之類的, 可以拿來做簡易的log訊息
補充: ThreadingMixIn跟ForkingMixIn差異是, Threading是每次呼叫個thread出來做事情, Forking是每次都會產生個process出來做事情, 不懂差異的要去查一下thread v.s process
其餘不錯的SocketServer範例教學: http://kmkeen.com/socketserver/2009-02-07-07-52-15.html
以上
Python SocketServer: http://docs.python.org/2/library/socketserver.html
官網算是有一些範例, 而且網路上也有一隻影片有簡易教學
youtube 英文教學: http://www.youtube.com/watch?v=OU7AWyw8MfI
基本上SocketServer是大幅簡化了我們要寫Socket Server的module,
他基本支援四種server classes TCPServer, UDPServer, UnixStreamServer, UnixDatagramServer
前兩種很常見, 而後兩種是純Linux使用, 差在一個起始是AF_INET還是AF_UNIX
而SocketServer module如果在預設的情況下是同步的設定, 也就是一個服務處理一個connection
那如果你有多個需求或者講非同步的處理, 可能有的在處理連線有的在處理其他工作, 就可以使用ThreadingMixIn or ForkingMixIn 來幫你解決這類問題
所以要建立一個SocketServer, 有幾個必要步驟
1. 因為既然要寫SocketServer, 就會有相對應的服務要處理, 所以要先建立一個request handler去繼承RequestHandler (這個有幾種種類), 用來實作你要怎麼處理進入的要求
2. 當然你也要有建立一個上述所說的socket class, 並且附上剛剛建立的request handler
3. 有了前面兩個設定之後, 就可以呼叫andle_request() or serve_forever()來幫你開始SocketServer的服務
看起來內容很多而且不小心寫的太像翻譯, 用一點例子輔助說明, 第一個範例我拿官網的解釋
import SocketServer class MyTCPHandler(SocketServer.BaseRequestHandler): def handle(self): self.data = self.request.recv(1024).strip() print "{} wrote:".format(self.client_address[0]) print self.data self.request.sendall(self.data.upper()) if __name__ == "__main__": HOST, PORT = "localhost", 9999 server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler) server.serve_forever()
我拿掉註解, 首先這程式很小, 而且照剛剛三步驟就真的寫完了
1. 有一個MyTCPHandler去繼承BaseRequestHandler(有其他更好用的後續提), 然後實作handler要做甚麼就可以, 這邊很單純, 他收client端傳過訊息, 印出傳過來的訊息之後, 再把這訊息變大寫傳出去, 而且用sendall, 所以所有有連線的client都會收到此訊息大寫版
2. 建立SocketServer.TCPServer((HOST, PORT), MyTCPHandler), 這件事情會建立socket也會將剛剛的request handler傳入
3. 呼叫serve_forever, 程式就開始跑了 (想成之前範例的while True)
幾個東西稍微說明一下
self.client_address就是client的位址, 跟當初的accpet()回傳的結果是一樣的
self.request其實就是當初用socket建立出來的socket物件, 所以也可以用self.request.getpeername()去取得client位址, 跟上述一樣
超簡單的範例, 不過, 因為太簡單, 有很多事情還不太方便, 例如說, 我想要避免之前因為中斷結果又會造成connection問題, 或者是需要threading, 所以下面再提供一個稍微小複雜的範例
import SocketServer, sys, threading from time import ctime HOST= '' PORT = 12345 class MyServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): daemon_threads = True allow_reuse_address = True class MyHandler(SocketServer.StreamRequestHandler): def handle(self): cur = threading.current_thread() print '[%s] Client connected from %s and [%s] is handling with him.' % (ctime(), self.request.getpeername(), cur.name) while True: msg = self.request.recv(1024).strip() if not msg: pass else: print "Client send: " + msg self.wfile.write("You say: " + msg + "\r\n") self.request.close() if __name__ == '__main__': server = MyServer((HOST,PORT), MyHandler) ip, port = server.server_address print "Server is starting at:", (ip, port) try: server.serve_forever() except KeyboardInterrupt: sys.exit(0)
這範例一樣很笨, 只是在server紀錄一下誰連過來, 然後跟他問聲好XD
不過我額外連Server端都重新繼承了, 除了繼承了ThreadingMixIn之外, 我設定了兩件事情
1. daemon_thread = True, 也就是當main thread死, 其餘thread都跟著死, 不設定開的話, 如果用ctrl+C去中止程式是中止不了的, 以server來講, server thread都中止了, 剩下的理應也沒有理由活著了 (要死一起死!!)
2. allow_reuse_address = True, 你看多貼心, 這次讓你可以設定是不是要reuse address
那我有在main那邊簡單做個try~except, 只是要抓ctrl+C的命令, 有的話就程式結束
而在Handler那端, 拿前幾篇的範例使用, 不過多做了一些訊息log, 像這邊有一個threading.current_thread
這個會取得在這時候運作的thread基本資訊, 例如名稱之類的, 可以拿來做簡易的log訊息
補充: ThreadingMixIn跟ForkingMixIn差異是, Threading是每次呼叫個thread出來做事情, Forking是每次都會產生個process出來做事情, 不懂差異的要去查一下thread v.s process
其餘不錯的SocketServer範例教學: http://kmkeen.com/socketserver/2009-02-07-07-52-15.html
以上
請問若是server要對外開放(其他電腦能夠連上server),需要作什麼樣的修改?
回覆刪除對於這塊不是很有概念@@
請指教了 謝謝
簡單來說, 如果HOST設定localhost, 那就只有本機自己才連的到, 如果HOST設定空字串, 照理講就可以開放給對外連線了, 只是要確定防火牆沒有擋住
刪除