1、socket概念
? Socket是應用層與TCP/IP協議族通信的中間軟體抽象層,它是一組介面,在設計模式中,Socket其實就是一個門面模式,它把復雜的TCP/IP協議族隱藏在Socket介面后面,對用戶來說,一組簡單的介面就是全部,讓Socket去組織資料,以符合指定的協議,

其實可以認為,socket就是一個模塊,我們通過呼叫該模塊中已經實作的方法建立兩個行程之間的連接和通信,
也可以將socket認為是ip+port,因為ip是用來標識互聯網中的一臺主機的位置,而port是用來標識這臺機器上的一個應用程式,
所以我們只要確立了ip和port就能找到一個應用程式,并且使用socket模塊來與之通信,
2、socket(套接字)的發展史及種類
套接字起源于 20 世紀 70 年代加利福尼亞大學伯克利分校版本的 Unix,即人們所說的 BSD Unix, 因此,有時人們也把套接字稱為“伯克利套接字”或“BSD套接字”,一開始套接字被設計用在同 一臺主機上多個應用程式之間的通訊,這也被稱行程間通訊或 IPC,套接字有兩種(或者稱為有兩個種族,分別是基于檔案型的和基于網路型的,
基于檔案型別的套接字家族
套接字家族的名字:AF_UNIX
unix一切皆檔案,基于檔案的套接字呼叫的就是底層的檔案系統來取資料,兩個套接字行程運行在同一機器,可以通過訪問同一個檔案系統間接完成通信,
基于網路型別的套接字家族
套接字家族的名字:AF_INET
(還有AF_INET6被用于ipv6,還有一些其他的地址家族,不過,他們要么是只用于某個平臺,要么就是已經被廢棄,或者是很少被使用,或者是根本沒有實作,所有地址家族中,AF_INET是使用最廣泛的一個,python支持很多種地址家族,但對于網路編程而言,大部分時候只使用AF_INET)
3、TCP 協議和 UDP 協議
TCP(Transmission Control Protocol)可靠的、面向連接的協議、傳輸效率低全雙工通信(發送快取&接收快取)、面向位元組流,使用TCP的應用:Web瀏覽器;電子郵件、檔案傳輸程式,
UDP(User Datagram Protocol)不可靠的、無連接的服務,傳輸效率高(發送前時延小),一對一、一對多、多對一、多對多、面向報文,盡最大努力服務,無擁塞控制,使用UDP的應用:域名系統 (DNS);視頻流;IP語音(VoIP),

4、socket(套接字)初使用
(1)、基于TCP協議的socket
<1>、 服務器端
import socket
sk = socket.socket() # 創建一個服務器的套接字
sk.bind(('127.0.0.1',9001)) # 系結一個地址 IP +埠
sk.listen() # 開始監聽客戶端的請求
# 127.0.0.1 永遠標識本機地址
# 不過交換機的 可以在撰寫代碼的程序中排除一些網路問題
conn,addr = sk.accept() # 接收一個連接請求
conn.send(b'hello') # 向客戶端發送資訊
msg = conn.recv(1024).decode('utf-8') # 接收客戶端資訊,并限制了接收位元組的個數
print(msg)
conn.close() # 結束與對方的資訊傳遞
sk.close() # 關閉服務器套接字
<2>、 客戶端
import socket
sk = socket.socket() # 創建客戶套接字
sk.connect(('127.0.0.1',9001)) # 嘗試連接服務器 IP +埠
msg = sk.recv(23) # 對話(發送/接收)
print(msg)
sk.send('你好'.encode('utf-8'))
sk.close() # 關閉客戶套接字
注意:
? TCP是基于連接的,必須先啟動服務器端,然后在再啟動客戶端去連接服務端,
? UDP是無連接的,啟動服務之后可以直接接受訊息,不需要提前建立鏈接,
# 在重啟服務端時有可能會遇到的報錯
OSError: [Error 48] Address already in use
# 解決辦法:加入一條socket配置,重用ip和埠
import socket
from socket import SOL_SOCKET,SO_REUSEADDR
sk = socket.socket()
sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) # 加入這個
sk.bind(('127.0.0.1',8898)) #把地址系結到套接字
···
(2)、基于UDP協議的socket
<1>、 服務器端
from socket import socket,SOCK_DGRAM
sk = socket(type=SOCK_DGRAM) # 創建一個服務器的套接字
sk.bind(('127.0.0.1',9001)) # 系結服務器套接字
while True:
msg,cli_addr = sk.recvfrom(1024) # 對話(接收與發送)
print(msg.decode('utf-8'))
msg = input('>>>')
if msg.upper() == 'Q':continue
sk.sendto(msg.encode('utf-8'),cli_addr)
<2>、 客戶端
from socket import socket,SOCK_DGRAM
sk = socket(type=SOCK_DGRAM)
server_addr = ('127.0.0.1',9001)
while True:
msg = input('>>>')
if msg.upper() == 'Q':
break
sk.sendto(msg.encode('utf-8'),server_addr)
msg = sk.recv(1024)
print(msg.decode('utf-8'))
5、socket 詳解
socket.socket(family=AF_INET,type=SOCK_STREAM,proto=0,fileno=None)
<1>、 創建socket物件的引數說明:
| family | 地址系列應為AF_INET(默認值),AF_INET6,AF_UNIX,AF_CAN或AF_RDS, (AF_UNIX 域實際上是使用本地 socket 檔案來通信) |
|---|---|
| type | 套接字型別應為SOCK_STREAM(默認值),SOCK_DGRAM,SOCK_RAW或其他SOCK_常量之一, SOCK_STREAM 是基于TCP的,有保障的(即能保證資料正確傳送到對方)面向連接的SOCKET,多用于資料傳送, SOCK_DGRAM 是基于UDP的,無保障的面向訊息的socket,多用于在網路上發廣播資訊, |
| proto | 協議號通常為零,可以省略,或者在地址族為AF_CAN的情況下,協議應為CAN_RAW或CAN_BCM之一, |
| fileno | 如果指定了fileno,則其他引數將被忽略,導致帶有指定檔案描述符的套接字回傳, 與socket.fromfd()不同,fileno將回傳相同的套接字,而不是重復的, 這可能有助于使用socket.close()關閉一個獨立的插座, |
<2>、 socket的更多方法介紹
# 服務端套接字函式
s.bind() # 系結(主機,埠號)到套接字
s.listen() # 開始TCP監聽
s.accept() # 被動接受TCP客戶的連接,(阻塞式)等待連接的到來
# 客戶端套接字函式
s.connect() # 主動初始化TCP服務器連接
s.connect_ex() # connect()函式的擴展版本,出錯時回傳出錯碼,而不是拋出例外
# 公共用途的套接字函式
s.recv() # 接收TCP資料
s.send() # 發送TCP資料
s.sendall() # 發送TCP資料
s.recvfrom() # 接收UDP資料
s.sendto() # 發送UDP資料
s.getpeername() # 連接到當前套接字的遠端的地址
s.getsockname() # 當前套接字的地址
s.getsockopt() # 回傳指定套接字的引數
s.setsockopt() # 設定指定套接字的引數
s.close() # 關閉套接字
# 面向鎖的套接字方法
s.setblocking() # 設定套接字的阻塞與非阻塞模式
s.settimeout() # 設定阻塞套接字操作的超時時間
s.gettimeout() # 得到阻塞套接字操作的超時時間
# 面向檔案的套接字的函式
s.fileno() # 套接字的檔案描述符
s.makefile() # 創建一個與該套接字相關的檔案
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/213514.html
標籤:其他
