socket基礎 什麼是socket? - socket為介面通道,內部封裝了IP地址、埠、協議等信息;我們可以看作是以前的通過電話機撥號上網的年代,socket即為電話線 socket通信流程 我們通過下麵的圖來瞭解socket的通信流程 流程描述: - 1 伺服器根據地址類型(ipv4,ipv ...
socket基礎
什麼是socket?
- socket為介面通道,內部封裝了IP地址、埠、協議等信息;我們可以看作是以前的通過電話機撥號上網的年代,socket即為電話線
socket通信流程
我們通過下麵的圖來瞭解socket的通信流程
流程描述:
- 1 伺服器根據地址類型(ipv4,ipv6)、socket類型、協議創建socket
- 2 伺服器為socket綁定ip地址和埠號
- 3 伺服器socket監聽埠號請求,隨時準備接收客戶端發來的連接,這時候伺服器的socket並沒有被打開
- 4 客戶端創建socket
- 5 客戶端打開socket,根據伺服器ip地址和埠號試圖連接伺服器socket
- 6 伺服器socket接收到客戶端socket請求,被動打開,開始接收客戶端請求,直到客戶端返回連接信息。這時候socket進入阻塞狀態,
所謂阻塞即accept()方法一直等到客戶端返回連接信息後才返回,開始接收下一個客戶端連接請求
- 7 客戶端連接成功,向伺服器發送連接狀態信息
- 8 伺服器accept方法返回,連接成功
- 9 客戶端向socket寫入信息(或服務端向socket寫入信息)
- 10 伺服器讀取信息(客戶端讀取信息)
- 11 客戶端關閉
- 12 伺服器端關閉
socket 方法
- socket 方法中有兩個參數:family、type
family 的參數來確定伺服器之間的通信
- family = AF_INET : 伺服器之間的通信
- family = AF_INET6 :伺服器之間的通信
- family = AF_UNIX : UNIX系統中的進程間的通信
type 的參數來確定連接協議
- type = SOCK_STREAM : 用來建立 TCP
- type = SOCK_Dgram : 用來建立 UDP
其他方法
sk.bind(address) #s.bind(address) 將套接字綁定到地址。address地址的格式取決於地址族。在AF_INET下,以元組(host,port)的形式表示地址。 sk.listen(backlog) #開始監聽傳入連接。backlog指定在拒絕連接之前,可以掛起的最大連接數量。 #backlog等於5,表示內核已經接到了連接請求,但伺服器還沒有調用accept進行處理的連接個數最大為5 #這個值不能無限大,因為要在內核中維護連接隊列 sk.setblocking(bool) #是否阻塞(預設True),如果設置False,那麼accept和recv時一旦無數據,則報錯。 sk.accept() #接受連接並返回(conn,address),其中conn是新的套接字對象,可以用來接收和發送數據。address是連接客戶端的地址。 #接收TCP 客戶的連接(阻塞式)等待連接的到來 sk.connect(address) #連接到address處的套接字。一般,address的格式為元組(hostname,port),如果連接出錯,返回socket.error錯誤。 sk.connect_ex(address) #同上,只不過會有返回值,連接成功時返回 0 ,連接失敗時候返回編碼,例如:10061 sk.close() #關閉套接字 sk.recv(bufsize[,flag]) #接受套接字的數據。數據以字元串形式返回,bufsize指定最多可以接收的數量。flag提供有關消息的其他信息,通常可以忽略。 sk.recvfrom(bufsize[.flag]) #與recv()類似,但返回值是(data,address)。其中data是包含接收數據的字元串,address是發送數據的套接字地址。 sk.send(string[,flag]) #註意send發送的數據必須為byte #將string中的數據發送到連接的套接字。返回值是要發送的位元組數量,該數量可能小於string的位元組大小。即:可能未將指定內容全部發送。 sk.sendall(string[,flag]) #將string中的數據發送到連接的套接字,但在返回之前會嘗試發送所有數據。成功返回None,失敗則拋出異常。 #內部通過遞歸調用send,將所有內容發送出去。 sk.sendto(string[,flag],address) #將數據發送到套接字,address是形式為(ipaddr,port)的元組,指定遠程地址。返回值是發送的位元組數。該函數主要用於UDP協議。 sk.settimeout(timeout) #設置套接字操作的超時期,timeout是一個浮點數,單位是秒。值為None表示沒有超時期。一般,超時期應該在剛創建套接字時設置,因為它們可能用於連接的操作(如 client 連接最多等待5s ) sk.getpeername() #返回連接套接字的遠程地址。返回值通常是元組(ipaddr,port)。 sk.getsockname() #返回套接字自己的地址。通常是一個元組(ipaddr,port) sk.fileno() #套接字的文件描述符
簡單實現兩端聊天
------------------伺服器端------------------ import socket # 創建socket對象,socket 預設的參數為 family = AF_INET 、type = SOCK_STREAM sk = socket.socket() address = ('127.0.0.1',8000) # 綁定IP地址與埠 sk.bind(address) # 最大的等待數為5 sk.listen(5) print('server is waiting...') # 進行阻塞,等待客戶端來連接 conn,addr = sk.accept() # conn 為客戶端的socket對象 inp = input('>>>') conn.send(bytes(inp,'utf-8')) # conn.close() # 關閉與客戶端的鏈接 ------------------------------------------- -------------------客戶端------------------- import socket sk = socket.socket() address = ('127.0.0.1',8000) sk.connect(address) # 連接進入服務端 # recv也會進行阻塞,recv一次接收的內容最大為1024k data = sk.recv(1024) print(str(data,'utf-8'))
上述例子,我們實現了服務端與客戶端的連接,併進行了聊天;
- 首先,我們需要先打開服務端,此時服務端會進行阻塞,等待客戶端的接入
- 接著,我們就可以打開客戶端連入服務端,此時即可以開始聊天
在往後,我們還會學到服務端的併發聊天、遠程操作、文件上傳等相關操作