1、TCP sorcket:
server side(服務器端):
1 import SocketServer 2 class MyTCPHandler(SocketServer.BaseRequestHandler): 3 def handle(self): 4 self.data=self.request.recv(1024).strip() 5 print "{} wrote".format(self.client_address[0]) 6 print self.data 7 self.request.sendall(self.data.upper()) 8 if __name__=="__main__": 9 HOST,PORT="localhost",9999 10 server=SocketServer.TCPServer((HOST,PORT),MyTCPHandler) 11 server.serve_forever()
解釋:
第1句引進相關模塊;
第2句定義類MyTCPHandler,它是繼承自SocketServer的BaseRequestHandler類,該類還有相關的子類,下面會用到;
第3句重寫基類的handle()方法,有很多屬性可以直接用,比如self.request,請求,self.request.recv(1024).strip()的意思是從客戶端的請求那得到最大1kb的數據,並且數據.strip(),去掉前后的空格,中間的不會去掉的;
self.client_adress是客戶端的地址;
第7句是把得到的數據轉換成大寫發給客戶端;
第8句是只有在直接運行當前程序是才會運行到的;
HOST、PORT是主機地址和端口號;
第10句就是創建一個server對象,是基於TCPServer類創建的;
11句是啟動服務監聽的意思;
上面是一種創建TCP server的方法,下面還有一種基於BaseRequestHandler基類StreamRequestHandler,當然它還有一個基類DatagramRequestHandler,兩者有區別。
1 import SocketServer 2 class MyTCPHandler(SocketServer.StreamRequestHandler): 3 def handle(self): 4 self.data=self.rfile.readline().strip() 5 print "{} wrote".format(self.client_address[0]) 6 print self.data 7 self.wfile.write(self.data.upper()) 8 if __name__=="__main__": 9 HOST,PORT="localhost",9999 10 server=SocketServer.TCPServer((HOST,PORT),MyTCPHandler) 11 server.serve_forever()
基本上與上面的相同,但是畢竟StreamRequestHandler是BaseRequestHandler的基類,所以有一些新的方法。
第4行,self.rfile.readline(), self.rfile類型是socket._fileobject,讀寫模式是"rb",方法有:read,readline,readlines,write(data),writelines(list),close,flush
readline()方法會多次調用recv()方法,直到讀取一行;其它的基本類似。
the client side(客戶端)
1 import socket 2 import sys 3 HOST,PORT="localhost",9999 4 data=" ".join(sys.argv[1:]) 5 sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 6 try: 7 sock.connect((HOST,PORT)) 8 sock.sendall(data+"\n") 9 received=sock.recv(1024) 10 finally: 11 sock.close() 12 print "Sent: {}".format(data) 13 print "Received: {}".format(received) 14 input()
重點:建立一個socket對象sock,socket.SOCK_STREAM說明建立的是一個TCP socket,用socket.SOCK_DGRAM是UDP socket。
sock.connect()方法是與主機建立連接,可見tcp協議是面向連接的可靠地通信協議,這正是tcp與udp協議的不同,udp協議是非面向連接的不可靠的協議,udp發送數據之前並不會與對方建立連接,而是直接發給對方。UDP適用於一次只傳送少量數據、對可靠性要求不高的應用環境。
比如,我們經常使用“ping”命令來測試兩台主機之間TCP/IP通信是否正常,其實“ping”命令的原理就是向對方主機發送UDP數據包,然后對方主機確認收到數據包,如果數據包是否到達的消息及時反饋回來,那么網絡就是通的。例如,在默認狀態下,一次“ping”操作發送4個數據包。大家可以看到,發送的數據包數量是4包,收到的也是4包(因為對方主機收到后會發回一個確認收到的數據包)。這充分說明了UDP協議是面向非連接的協議,沒有建立連接的過程。正因為UDP協議沒有連接的過程,所以它的通信效率高;但也正因為如此,它的可靠性不如TCP協議高。
QQ就使用UDP發消息,因此有時會出現收不到消息的情況。
下面我們就用python來實現UDP的通信協議。
udp服務器端:
1 import SocketServer 2 class MyUDPHandler(SocketServer.BaseRequestHandler): 3 def handle(self): 4 data=self.request[0].strip() 5 socket=self.request[1] 6 print "{} wrote".format(self.client_address[0]) 7 print data 8 socket.sendto(data.upper(),self.client_address) 9 if __name__=="__main__": 10 HOST,PORT="localhost",9999 11 server =SocketServer.UDPServer((HOST,PORT),MyUDPHandler) 12 server.serve_forever()
解釋:udp的server與tcp的有一定的區別,它的self.request含有一個data和一個socket,分別用self.request[0]和self.request[1]獲取,由於udp是面向非連接的協議,所以要用sendto()方法,並且要加上客戶端的地址。
udp客戶端:
1 import socket 2 import sys 3 HOST,PORT="localhost",9999 4 data=" ".join(sys.argv[1:]) 5 sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 6 sock.sendto(data+"\n",(HOST,PORT)) 7 received=sock.recv(1024) 8 print "Sent: {}".format(data) 9 print "Received: {}".format(received)
可以看出與tcp的客戶端相比,udp的sock並沒有連接過程,直接發送的數據。
運行,點擊運行服務器端.py的文件,然后在命令行下:python d:/py/client.py hello world (根據自己的文件地址寫命令)回車就ok了,可以看到客戶端服務器端都有輸出數據。