Socket通信原理簡介
何謂socket
計算機,顧名思義即是用來做計算。因而也需要輸入和輸出,輸入需要計算的條件,輸出計算結果。這些輸入輸出可以抽象為I/O(input output)。
Unix的計算機處理IO是通過文件的抽象。計算機不同的進程之間也有輸入輸出,也就是通信。因此這這個通信也是通過文件的抽象文件描述符來進行。
在同一台計算機,進程之間可以這樣通信,如果是不同的計算機呢?網絡上不同的計算機,也可以通信,那么就得使用網絡套接字(socket)。socket就是在不同計算機之間進行通信的一個抽象。他工作於TCP/IP協議中應用層和傳輸層之間的一個抽象。如下圖:

socket.jpg
服務器通信
socket保證了不同計算機之間的通信,也就是網絡通信。對於網站,通信模型是客戶端服務器之間的通信。兩個端都建立一個socket對象,然后通過socket對象對數據進行傳輸。通常服務器處於一個無線循環,等待客戶端連接:

socket3.jpg
socket 通信實例
socket接口是操作系統提供的,調用操作系統的接口。當然高級語言一般也封裝了好用的函數接口,下面用python代碼寫一個簡單的socket服務端例子:
server.py
import socket HOST = 'localhost' # 服務器主機地址 PORT = 5000 # 服務器監聽端口 BUFFER_SIZE = 2048 # 讀取數據大小 # 創建一個套接字 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 綁定主機和端口 sock.bind((HOST, PORT)) # 開啟socket監聽 sock.listen(5) print 'Server start, listening {}'.format(PORT) while True: # 建立連接,連接為建立的時候阻塞 conn, addr = sock.accept() while True: # 讀取數據,數據還沒到來阻塞 data = conn.recv(BUFFER_SIZE) if len(data): print 'Server Recv Data: {}'.format(data) conn.send(data) print 'Server Send Data: {}'.format(data) else: print 'Server Recv Over' break conn.close() sock.close()
client.py
import socket HOST = 'localhost' PORT = 5000 BUFFER_SIZE = 1024 # 創建客戶端套接字 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 連接到服務器 sock.connect((HOST, PORT)) try: message = "Hello" # 發起數據給服務器 sock.sendall(message) amount_received = 0 amount_expected = len(message) while amount_received < amount_expected: # 接收服務器返回的數據 data = sock.recv(10) amount_received += len(data) print 'Client Received: {}'.format(data) except socket.errno, e: print 'Socket error: {}'.format(e) except Exception, e: print 'Other exception: %s'.format(e) finally: print 'Closing connection to the server' sock.close()
TCP 三次握手
python代碼寫套接字很簡單。傳說的TCP三次握手又是如何體現的呢?什么是三次握手呢?
- 第一握:首先客戶端發送一個syn,請求連接,
- 第二握:服務器收到之后確認,並發送一個 syn ack應答
- 第三握:客戶端接收到服務器發來的應答之后再給服務器發送建立連接的確定。
用下面的比喻就是
C:約么?
S:約
C:好的
約會
這樣就建立了一個TCP連接會話。如果是要斷開連接,大致過程是:

tcp.png
上圖也很清晰的表明了三次握手的socket具體過程。
- 客戶端socket對象connect調用之后進行阻塞,此過程發送了一個syn。
- 服務器socket對象調用accept函數之后阻塞,直到客戶端發送來的syn,然后發送syn和ack應答
- 客戶端socket對象收到服務端發送的應答之后,再發送一個ack給服務器,並返回connect調用,建立連接。
- 服務器socket對象接受客戶端最后一次握手確定ack返回accept函數,建立連接。
至此,客戶端和服務器的socket通信連接建立完成,剩下的就是兩個端的連接對象收發數據,從而完成網絡通信。