天天看點

網絡程式設計——socket程式設計

  1.硬體c/s架構(列印機)

  2.軟體c/s架構 

    網際網路企業處處是c/s架構

  c/s架構與socket的關系:學習socket就是為了完成c/s架構的開發

  一個完整的計算系統是由硬體、作業系統、應用軟體三者組成。(這樣就可以自己和自己玩了)

  若想和别人一起玩,那就需要聯網了。

  網際網路的核心就是一堆協定組成,協定就是标準。例如:全世界官網通信的标準是英語。

  詳見網絡通信原理

  1、c/s架構的軟體(軟體屬于應用層)是基于網絡進行通信的

  2、網絡的核心即一堆協定,協定即标準,你想開發一款基于網絡通信的軟體,就必須遵循這些标準。

  3、從這些标準開始研究,開啟我們的socket程式設計之旅

網絡程式設計——socket程式設計

   socket是應用層與tcp/ip協定族通信的中間軟體抽象層,它是一組接口。在設計模式中,socket其實就是一種門面模式,它把複雜的tcp/ip協定族隐藏在socket接口後面,對使用者來說,一組簡單的接口就是全部,讓socket取組織資料,以符合指定的協定。

  我們無需深入了解tcp/udp協定,socket已經為我們封裝好了,我們隻需要遵循socket的規定去程式設計,寫出的程式自然就是遵循tcp/udp标準的。

  套接字起源于 20 世紀 70 年代加利福尼亞大學伯克利分校版本的 unix,即人們所說的 bsd unix。 是以,有時人們也把套接字稱為“伯克利套接字”或“bsd 套接字”。一開始,套接字被設計用在同 一台主機上多個應用程式之間的通訊。這也被稱程序間通訊,或 ipc。套接字有兩種(或者稱為有兩個種族),分别是基于檔案型的和基于網絡型的。 

  套接字家族的名字:af_unix

  unix一切皆檔案,基于檔案的套接字調用的就是底層的檔案系統來取資料,兩個套接字程序運作在同一機器,可以通過通路同一個檔案系統間接完成通信

  套接字家族的名字:af_inet

  (還有af_inet6被用于ipv6,還有一些其他的位址家族,不過,他們要麼是隻用于某個平台,要麼就是已經被廢棄,或者是很少被使用,或者是根本沒有實作,所有位址家族中,af_inet是使用最廣泛的一個,python支援很多種位址家族,但是由于我們隻關心網絡程式設計,是以大部分時候我麼隻使用af_inet)

網絡程式設計——socket程式設計

先從伺服器端說起。伺服器端先初始化socket,然後與端口綁定(bind),對端口進行監聽(listen),調用accept阻塞,等待用戶端連接配接。在這時如果有個用戶端初始化一個socket,然後連接配接伺服器(connect),如果連接配接成功,這時用戶端與伺服器端的連接配接就建立了。用戶端發送資料請求,伺服器端接收請求并處理請求,然後把回應資料發送給用戶端,用戶端讀取資料,最後關閉連接配接,一次互動結束

網絡程式設計——socket程式設計
網絡程式設計——socket程式設計

view code

  tcp是基于連結的,必須先啟動服務端,然後再啟動用戶端去連結服務端

  由于你的服務端仍然存在四次揮手的time_wait狀态在占用位址

    如果不懂,請深入研究1.tcp三次握手,四次揮手 ;2.syn洪水攻擊 ;3.伺服器高并發情況下會有大量的time_wait狀态的優化方法

  解決辦法:

網絡程式設計——socket程式設計
網絡程式設計——socket程式設計

方法一

網絡程式設計——socket程式設計
網絡程式設計——socket程式設計

方法二

  udp是無連結,先啟動哪一端都不會錯

網絡程式設計——socket程式設計
網絡程式設計——socket程式設計

server.py

網絡程式設計——socket程式設計
網絡程式設計——socket程式設計

client.py

網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計

client1.py

網絡程式設計——socket程式設計
網絡程式設計——socket程式設計

client2.py

網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計

讓我們基于tcp先制作一個遠端執行指令的程式(1:執行錯誤指令 2:執行ls 3:執行ifconfig)

注意注意注意:

res=subprocess.popen(cmd.decode('utf-8'),

shell=true,

stderr=subprocess.pipe,

stdout=subprocess.pipe)

的結果的編碼是以目前所在的系統為準的,如果是windows,那麼res.stdout.read()讀出的就是gbk編碼的,在接收端需要用gbk解碼

且隻能從管道裡讀一次結果

注意:有些指令既有正确的輸出,也有錯誤的輸出。例如:指令ls -l ; lllllll ; pwd 的結果是既有正确stdout結果,又有錯誤stderr結果

網絡程式設計——socket程式設計
網絡程式設計——socket程式設計

服務端

網絡程式設計——socket程式設計
網絡程式設計——socket程式設計

用戶端

網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計

  注意:隻有tcp有粘包現象,udp永遠不會粘包

網絡程式設計——socket程式設計

發送端可以是一k一k地發送資料,而接收端的應用程式可以兩k兩k地提走資料,當然也有可能一次提走3k或6k資料,或者一次隻提走幾個位元組的資料,也就是說,應用程式所看到的資料是一個整體,或說是一個流(stream),一條消息有多少位元組對應用程式是不可見的,是以tcp協定是面向流的協定,這也是容易出現粘包問題的原因。而udp是面向消息的協定,每個udp段都是一條消息,應用程式必須以消息為機關提取資料,不能一次提取任意位元組的資料,這一點和tcp是很不同的。怎樣定義消息呢?可以認為對方一次性write/send的資料為一個消息,需要明白的是當對方send一條資訊的時候,無論底層怎樣分段分片,tcp協定層會把構成整條消息的資料段排序完成後才呈現在核心緩沖區。

例如基于tcp的套接字用戶端往服務端上傳檔案,發送時檔案内容是按照一段一段的位元組流發送的,在接收方看了,根本不知道該檔案的位元組流從何處開始,在何處結束

所謂粘包問題主要還是因為接收方不知道消息之間的界限,不知道一次性提取多少位元組的資料所造成的。

此外,發送方引起的粘包是由tcp協定本身造成的,tcp為提高傳輸效率,發送方往往要收集到足夠多的資料後才發送一個tcp段。若連續幾次需要send的資料都很少,通常tcp會根據優化算法把這些資料合成一個tcp段後一次發送出去,這樣接收方就收到了粘包資料。

tcp(transport control protocol,傳輸控制協定)是面向連接配接的,面向流的,提供高可靠性服務。收發兩端(用戶端和伺服器端)都要有一一成對的socket,是以,發送端為了将多個發往接收端的包,更有效的發到對方,使用了優化方法(nagle算法),将多次間隔較小且資料量小的資料,合并成一個大的資料塊,然後進行封包。這樣,接收端,就難于分辨出來了,必須提供科學的拆包機制。 即面向流的通信是無消息保護邊界的。

udp(user datagram protocol,使用者資料報協定)是無連接配接的,面向消息的,提供高效率服務。不會使用塊的合并優化算法,, 由于udp支援的是一對多的模式,是以接收端的skbuff(套接字緩沖區)采用了鍊式結構來記錄每一個到達的udp包,在每個udp包中就有了消息頭(消息來源位址,端口等資訊),這樣,對于接收端來說,就容易進行區分處理了。 即面向消息的通信是有消息保護邊界的。

tcp是基于資料流的,于是收發的消息不能為空,這就需要在用戶端和服務端都添加空消息的處理機制,防止程式卡住,而udp是基于資料報的,即便是你輸入的是空内容(直接回車),那也不是空消息,udp協定會幫你封裝上消息頭,實驗略

udp的recvfrom是阻塞的,一個recvfrom(x)必須對唯一一個sendinto(y),收完了x個位元組的資料就算完成,若是y>x資料就丢失,這意味着udp根本不會粘包,但是會丢資料,不可靠

tcp的協定資料不會丢,沒有收完包,下次接收,會繼續上次繼續接收,己端總是在收到ack時才會清除緩沖區内容。資料是可靠的,但是會粘包。

網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計
網絡程式設計——socket程式設計

繼續閱讀