網路編程之Socket
- 2019 年 10 月 3 日
- 筆記
網路編程之Socket
我們已經知道,假設我現在要寫一個程式,給另一台電腦發數據,必須通過tcp/ip協議 ,但具體的實現過程是什麼呢?我應該怎麼操作才能把數據封裝成tcp/ip的包,又執行什麼指令才能把數據發到對端機器上呢? 不能只有世界觀,沒有方法論呀。。。此時,socket隆重登場,簡而言之,socket這個東東乾的事情,就是幫你把tcp/ip協議層的各種數據封裝啦、數據發送、接收等通過程式碼已經給你封裝好了,你只需要調用幾行程式碼,就可以給別的機器發消息了。
一、Socket介紹
1、什麼是Socket
Socket是應用層與TCP/IP協議族通訊的中間軟體抽象層。它是一組介面。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket介面後面,對用戶來說,一組簡單的介面就是全部。
socket起源於Unix,而Unix/Linux基本哲學之一就是「一切皆文件」,都可以用「打開open –> 讀寫write/read –> 關閉close」模式 來操作。Socket就是該模式的一個實現,socket即是一種特殊的文件,一些socket函數就是對其進行的操作(讀/寫IO、打開、關閉)。
你想給另一台電腦發消息,你知道他的IP地址,他的機器上同時運行著qq、迅雷、word、瀏覽器等程式,你想給他的qq發消息,那想一下,你現在只能通過ip找到他的機器,但如果讓這台機器知道把消息發給qq程式呢?答案就是通過port,一個機器上可以有0-65535個埠,你的程式想從網路上收發數據,就必須綁定一個埠,這樣,遠程發到這個埠上的數據,就全會轉給這個程式。
2、Socket通訊套路
當通過socket建立起2台機器的連接後,本質上socket只干2件事,一是收數據,一是發數據,沒數據時就等著。
socket 建立連接的過程跟我們現實中打電話比較像,打電話必須是打電話方和接電話方共同完成的事情,我們分別看看他們是怎麼建立起通話的。
接電話方:
1.首先你得有個電話 2.你的電話要有號碼 3.你的電話必須連上電話線 4.開始在家等電話 5.電話鈴響了,接起電話,聽到對方的聲音
打電話方:
1.首先你得有個電話 2.輸入你想撥打的電話 3.等待對方接聽 4.say 「hi 約么,我有七天酒店的打折卡噢~」 5.等待回應——》響應回應——》等待回應。。。。
把上述事件翻譯成socket通訊
接電話方(socket伺服器端):
1.首先你得有個電話(生成socket對象) 2.你的電話要有號碼(綁定本機ip+port) 3.你的電話必須連上電話線(連網) 4.開始在家等電話(開始監聽電話listen) 5.電話鈴響了,接起電話,聽到對方的聲音(接受新連接)
打電話方(socket客戶端):
1.首先你得有個電話(生成socket對象) 2.輸入你想撥打的電話(connect 遠程主機ip+port) 3.等待對方接聽 4.say 「hi 約么,我有七天酒店的打折卡噢~」(send() 發消息。。。) 5.等待回應——》響應回應——》等待回應。。。。
二、Socket套接字方法
1、socket實例類
socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
family(socket家族)
socket.AF_UNIX
:用於本機進程間通訊,為了保證程式安全,兩個獨立的程式(進程)間是不能互相訪問彼此的記憶體的,但為了實現進程間的通訊,可以通過創建一個本地的socket來完成。socket.AF_INET
:(還有AF_INET6被用於ipv6,還有一些其他的地址家族,不過,他們要麼是只用於某個平台,要麼就是已經被廢棄,或者是很少被使用,或者是根本沒有實現,所有地址家族中,AF_INET是使用最廣泛的一個,python支援很多種地址家族,但是由於我們只關心網路編程,所以大部分時候我么只使用AF_INET)。
socket type 類型
socket.SOCK_STREAM
# for TCPscoket.SOCK_DGRAM
# for UDPsocket.SOCK_RAW
# 原始套接字,普通的套接字無法處理ICMP、IGMP等網路報文,而SOCK_RAW可以;其次,SOCK_RAW也可以處理特殊的IPv4報文;此外,利用原始套接字,可以通過IP_HDRINCL套接字選項由用戶構造IP頭。socket.SOCK_RDM
# 是一種可靠的UDP形式,即保證交付數據但不保證順序。SOCK_RAM用來提供對原始協議的低級訪問,在需要執行某些特殊操作時使用,如發送ICMP報文。SOCK_RAM通常僅限於高級用戶或管理員運行的程式使用。socket.SOCK_SEQPACKET
# 廢棄了。
Only SOCK_STREAM and SOCK_DGRAM appear to be generally useful.
proto=0
可忽略,特殊用途才考慮。
fileno=None
可忽略,特殊用途才考慮。
2、服務端套接字函數
設s為socket實例化的一個對象
s.bind()
綁定(主機,埠號)到套接字。s.listen()
開始TCP監聽。s.accept()
被動接收TCP客戶的連接,(阻塞式)等待連接的到來。
3、客戶端套接字函數
設s為socket實例化的一個對象
s.connect()
主動初始化TCP伺服器連接。s.connect_ex()
是connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常。
4、公共用途的套接字函數
設s為socket實例化的一個對象
s.recv()
接收數據。s.send()
發送數據(send在待發送數據量大於己端快取區剩餘空間時,數據丟失,不會發完)s.sendall()
發送完整的TCP數據(本質就是循環調用send,sendall在待發送數據量大於己端快取區剩餘空間時,數據不丟失,循環調用send直到發完)。s.recvform()
Receive data from the socket. The return value is a pair (bytes, address)s.getpeername()
連接到當前套接字的遠端的地址。s.close()
關閉套接字。socket.setblocking(flag)
# True or False,設置socket為非阻塞模式。socket.getaddrinfo(host, port, family=0, type=0, proto=0, flags=0)
返回遠程主機的地址資訊,例如:socket.getaddrinfo('luffycity.com', 80)
。socket.getqdn()
拿到本機的主機名。socket.gethostbyname()
通過域名解析ip地址。