一 、Socket 套接字:通訊端點 簡介

socket起源於Unix,而Unix/Linux基本哲學之一就是「一切皆文件」,對於文件用【打開】【讀寫】【關閉】模式來操作。socket就是該模式的一個實現,socket即是一種特殊的文件,一些socket函數就是對其進行的操作(讀/寫IO、打開、關閉)。

Socket 是任何一種計算機網路通訊中最基礎的內容。Socket通訊一般用戶C/S結構系統的網路通訊。

Socket 網路通訊是基於TCP(傳輸控制協議)或UDP(用戶數據報協議)兩種協議通訊,所以有 面向連接(TCP )與無連接(UDP ) 兩種通訊方式。

Python 要創建TCP 套接字就得在創建的時候,指定套接字類型為SOCK_STREAM,它使用 TCP/IP通訊協議。

Python 要創建UDP 套接字就得在創建的時候,指定套接字類型為SOCK_DGRAM,它使用UDP/IP通訊協議。

其他關於 客戶/伺服器 的知識這裡不多講。

二、socket 參數與方法簡介

1.參數說明

創建服務端socket方法:socket(family, type, proto=0)

family 參數:地址簇

值可以是AF_UNIX ,AF_INET,AF_INET6,默認AF_INET;
AF_INET基於IPv4;
AF_INET6基於IPv4;
AF_UNIX 只能用於Unix系統之間通訊。

type參數:類型

值可以是SOCK_STREAM ,SOCK_DGRAM,SOCK_RAW,SOCK_RDM,SOCK_SEQPACKET ,默認值SOCK_STREAM;
SOCK_STREAM 流式socket 基於TCP 協議;
SOCK_DGRAM 數據報式socket 基於 UDP協議;
SOCK_RAW 原始套接字,普通的套接字無法處理ICMP、IGMP等網路報文,而SOCK_RAW可以;其次,SOCK_RAW也可以處理特殊的IPv4報文;此外,利用原始套接字,可以通過IP_HDRINCL套接字選項由用戶構造IP頭。
SOCK_RDM 是一種可靠的UDP形式,即保證交付數據報但不保證順序。SOCK_RAM用來提供對原始協議的低級訪問,在需要執行某些特殊操作時使用,如發送ICMP報文。SOCK_RAM通常僅限於高級用戶或管理員運行的程序使用。
SOCK_SEQPACKET 可靠的連續數據包服務。

proto參數:協議

0  (默認)與特定的地址家族相關的協議,如果是 0 ,則系統就會根據地址格式和套接類別,自動選擇一個合適的協議。

2. 方法簡介

伺服器端套接字函數

socket.bind( tuple) 綁定地址(主機,埠號對)到套接字

socket.listen( n ) 開始TCP 監聽, n表示最多允許n個連接同時連接進來

socket.accept() 被動接受TCP 客戶的連接,(阻塞式)等待連接的到來

客戶端套接字函數

socket.connect() 主動初始化TCP 伺服器連接

socket.connect_ex() connect()函數的擴展版本,出錯時返回出錯碼,而不是拋異常

公共用途的套接字函數

socket.recv() 接收TCP 數據

socket.send() 發送TCP 數據

socket.sendall() 完整發送TCP 數據

socket.recvfrom() 接收UDP 數據

socket.sendto() 發送UDP 數據

socket.getpeername() 連接到當前套接字的遠端的地址

socket.getsockname() 當前套接字的地址

socket.getsockopt() 返回指定套接字的參數

socket.setsockopt() 設置指定套接字的參數

socket.close() 關閉套接字

面向阻塞的套接字方法

socket.setblocking() 設置套接字的阻塞與非阻塞模式

socket.settimeout() 設置阻塞套接字操作的超時時間

socket.gettimeout() 得到阻塞套接字操作的超時時間

面向文件的套接字的函數

socket.fileno() 套接字的文件描述符

socket.makefile() 創建一個與該套接字關連的文件

三、創建TCP伺服器通訊端

服務端與客戶端通訊流程圖

服務端創建鏈接流程解析:

創建伺服器套接字(ss = socket())

把地址綁定到套接字上(ss.bind())

監聽連接(ss.listen())

伺服器無限循環(inf_loop:)

接受客戶的連接(cs = ss.accept())

通訊循環(comm_loop:)

對話(接收與發送)(cs.recv()/cs.send())

關閉客戶套接字(cs.close())

關閉伺服器套接字(ss.close())(可選)

示例:創建一個能接收客戶的消息,在消息前加一個時間戳後返回的TCP 伺服器。

socket_server.py

from socket import socket
from time import ctime

HOST =
PORT = 4444
BUFSIZ = 1024
ADDR = (HOST, PORT)

tcpSerSock = socket() # 創建伺服器套接字
tcpSerSock.bind(ADDR) # 把地址綁定到套接字上
tcpSerSock.listen() # 監聽連接

while True: # 伺服器無限循環
print(等待連接...)
tcpCliSock, addr = tcpSerSock.accept() # 接受客戶的連接
print(連接地址, addr)

while True: # 通訊循環
data = tcpCliSock.recv(BUFSIZ) # 接收TCP 數據
if not data:
break
tcpCliSock.send([%s] %s % (ctime(), data)) # 發送TCP 數據

tcpCliSock.close() # 關閉客戶套接字
tcpSerSock.close() # 關閉伺服器套接字

四、創建TCP客戶機通訊端

客服端創建鏈接流程解析:

創建客戶套接字(cs = socket())

嘗試連接伺服器(cs.connect()))

通訊循環(comm_loop:)

對話(接收與發送)(cs.send()/cs.recv())

關閉客戶套接字(cs.close())

示例:與前面socket_server.py 進行通訊

socket_client.py

from socket import *

HOST = 127.0.0.1 # 伺服器連接地址
PORT = 4444 # 伺服器啟用埠
BUFSIZ = 1024 # 緩衝區大小
ADDR = (HOST, PORT)

tcpClientSocket = socket(AF_INET, SOCK_STREAM) # 創建客戶端連接
tcpClientSocket.connect(ADDR) # 綁定頂服務端地址

while True: # 通訊循環
sendData = bytes(input(> ), encoding="UTF-8") # 輸入通訊內容,需要進行轉換
if not sendData: # 無發送數據退出
break
tcpClientSocket.send(sendData) # 發送通訊內容
recvData = tcpClientSocket.recv(BUFSIZ) # 接收返回的通訊數據
if not recvData: # 無接收數據退出
break
print(recvData) # 列印返回的通訊數據

tcpClientSocket.close() # 關閉客服端連接

五、運行客戶端與伺服器程序

  1. 先運行伺服器端程序 (win系統 cmd 窗口命令 python socket_server.py )。
  2. 再運行客戶端程序 (win系統 重新開 cmd 窗口 命令 python socket_client.py )。
  3. 在客戶端程序輸入內容 Hi woodman 。

服務端輸出內容:

等待連接...

連接 (127.0.0.1, 28520)等待連接...

客戶端輸出內容:

[Wed Oct 10 20:27:21 2018] Hi woodman

伺服器與客戶端通訊流程

  1. 伺服器啟動埠監聽,監聽埠連接qingq
  2. 客戶端發送連接請求(TCP 3次握手)
  3. 當客戶端連接上伺服器時,伺服器端顯示『等待連接...』信息,並列印出連接地址。
  4. 在客戶端接受服務的時候,伺服器又回去等待其它客戶端的連接。
  5. 客戶端發送數據,伺服器對數據進行處理,發送返回數據到客戶端。
  6. 客戶端接收到數據,對數據進行處理並列印數據。
  7. 客戶端關閉連接,伺服器關閉與客戶端連接,繼續等待其他客戶端的連接。(TCP 四次分手)

推薦閱讀:

相關文章