socket網絡通信

1.網絡通信的簡介

1.1 什麼是網絡

  • 網絡就是一種輔助雙方或者多方能夠連接在一起的工具
  • 如果沒有網絡可想單機的世界是多麼的孤單

1.2 使用網絡的目的

  • 就是爲了聯通多方然後進行通信用的,即把數據從一方傳遞給另外一方

  • 前面的學習編寫的程序都是單機的,即不能和其他電腦上的程序進行通信

  • 爲了讓在不同的電腦上運行的軟件,之間能夠互相傳遞數據,就需要藉助網絡的功能

1.3 小總結

  • 使用網絡能夠把多方鏈接在一起,然後可以進行數據傳遞

  • 所謂的網絡編程就是,讓在不同的電腦上的軟件能夠進行數據傳遞,即進程之間的通信

二、ip地址

2.1 什麼是地址

  • 地址就是用來標記地點的

2.2 ip地址的作用

  • ip地址:用來在網絡中標記一臺電腦,比如192.168.1.1;在本地局域網上是唯一的。

2.3 ip地址的分類(瞭解即可)

  • 每一個IP地址包括兩部分:網絡地址和主機地址
  • 2.3.1 A類IP地址

    • 一個A類IP地址由1字節的網絡地址和3字節主機地址組成,網絡地址的最高位必須是“0”,

    • 地址範圍1.0.0.1-126.255.255.254

    • 二進制表示爲:00000001 00000000 00000000 00000001 - 01111110 11111111 11111111 11111110

    • 可用的A類網絡有126個,每個網絡能容納1677214個主機

  • 2.3.2 B類IP地址

    • 一個B類IP地址由2個字節的網絡地址和2個字節的主機地址組成,網絡地址的最高位必須是“10”,
    • 地址範圍128.1.0.1-191.255.255.254
    • 二進制表示爲:10000000 00000001 00000000 00000001 - 10111111 11111111 11111111 11111110
    • 可用的B類網絡有16384個,每個網絡能容納65534主機
  • 2.3.3 C類IP地址

    • 一個C類IP地址由3字節的網絡地址和1字節的主機地址組成,網絡地址的最高位必須是“110”

    • 範圍192.0.1.1-223.255.255.254

    • 二進制表示爲: 11000000 00000000 00000001 00000001 - 11011111 11111111 11111110 11111110

    • C類網絡可達2097152個,每個網絡能容納254個主機

  • 2.3.4 D類地址用於多點廣播

    • D類IP地址第一個字節以“1110”開始,它是一個專門保留的地址。
      它並不指向特定的網絡,目前這一類地址被用在多點廣播(Multicast)中
    • 多點廣播地址用來一次尋址一組計算機 s 地址範圍224.0.0.1-239.255.255.254
  • 2.3.5 E類IP地址

    • 以“1111”開始,爲將來使用保留

    • E類地址保留,僅作實驗和開發用

  • 2.3.6 私有ip

    • 在這麼多網絡IP中,國際規定有一部分IP地址是用於我們的局域網使用,也就
      是屬於私網IP,不在公網中使用的,它們的範圍是:
      10.0.0.0~10.255.255.255
      172.16.0.0~172.31.255.255
      192.168.0.0~192.168.255.255
  • 2.3.7 注意

    • IP地址127.0.0.1~127.255.255.255用於迴路測試,
      如:127.0.0.1可以代表本機IP地址,用http://127.0.0.1就可以測試本機中配置的Web服務器。

3.socket簡介

  • 3.1. 不同電腦上的進程之間如何通信

首要解決的問題是如何唯一標識一個進程,否則通信無從談起!
在1臺電腦上可以通過進程號(PID)來唯一標識一個進程,但是在網絡中這是行不通的。
其實TCP/IP協議族已經幫我們解決了這個問題,網絡層的“ip地址”可以唯一標識網絡中的主機,而傳輸層的“協議+端口”可以唯一標識主機中的應用進程(進程)。
這樣利用ip地址,協議,端口就可以標識網絡的進程了,網絡中的進程通信就可以利用這個標誌與其它進程進行交互
注意:
所謂進程指的是:運行的程序以及運行時用到的資源這個整體稱之爲進程(在講解多任務編程時進行詳細講解)
所謂進程間通信指的是:運行的程序之間的數據共享
後面課程中會詳細說到,像網絡層等知識,不要着急

  • 3.2. 什麼是socket

    • socket(簡稱 套接字) 是進程間通信的一種方式,它與其他進程間通信的一個主要不同是:
    • 它能實現不同主機間的進程間通信,我們網絡上各種各樣的服務大多都是基於 Socket 來完成通信的

    • 例如我們每天瀏覽網頁、QQ 聊天、收發 email 等等

  • 3.3. 創建socket

    • 在 Python 中 使用socket 模塊的函數 socket 就可以完成:

    • import socket

    • socket.socket(AddressFamily, Type)

    • 說明:函數 socket.socket 創建一個 socket,該函數帶有兩個參數:

      • Address Family:可以選擇 AF_INET(用於 Internet 進程間通信) 或者 AF_UNIX(用於同一臺機器進程間通信),實際工作中常用AF_INET
      • Type:套接字類型,可以是 SOCK_STREAM(流式套接字,主要用於 TCP 協議)或者 SOCK_DGRAM(數據報套接字,主要用於 UDP 協議)
        創建一個tcp socket(tcp套接字)
import socket

# 創建tcp的套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# ...這裏是使用套接字的功能(省略)...

# 不用的時候,關閉套接字
s.close()
創建一個udp socket(udp套接字)

說明
套接字使用流程 與 文件的使用流程很類似
創建套接字
使用套接字收/發數據
關閉套接字

4.socket 與udp、tcp/ip的聯繫

  • 4.1 什麼是TCP/IP、UDP?

    • 4.1.1TCP/IP(Transmission Control Protocol/Internet Protocol)即傳輸控制協議/網間協議,是一個工業標準的協議集,它是爲廣域網(WANs)設計的。

    • 4.1.2 UDP(User Data Protocol,用戶數據報協議)是與TCP相對應的協議。它是屬於TCP/IP協議族中的一種。

      這裏有一張圖,表明了這些協議的關係。圖一

      TCP/IP協議族包括運輸層、網絡層、鏈路層。現在你知道TCP/IP與UDP的關係了吧。

4.2 Socket是什麼呢?

  • Socket在哪裏呢?
    - 在上圖中,我們沒有看到Socket的影子,那麼它到底在哪裏呢?還是用圖來說話,一目瞭然。
    - 在這裏插入圖片描述
    • Socket是應用層與TCP/IP協議族通信的中間軟件抽象層,它是一組接口。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來說,一組簡單的接口就是全部,讓Socket去組織數據,以符合指定的協議。
      你會使用它們嗎?
    • 前人已經給我們做了好多的事了,網絡間的通信也就簡單了許多,但畢竟還是有挺多工作要做的。以前聽到Socket編程,覺得它是比較高深的編程知識,但是隻要弄清Socket編程的工作原理,神祕的面紗也就揭開了。
    • 一個生活中的場景。你要打電話給一個朋友,先撥號,朋友聽到電話鈴聲後提起電話,這時你和你的朋友就建立起了連接,就可以講話了。等交流結束,掛斷電話結束此次交談。 生活中的場景就解釋了這工作原理,也許TCP/IP協議族就是誕生於生活中,這也不一定。
      在這裏插入圖片描述
      服務器端先初始化Socket,然後與端口綁定(bind),對端口進行監聽(listen),調用accept阻塞,等待客戶端連接。在這時如果有個客戶端初始化一個Socket,然後連接服務器(connect),如果連接成功,這時客戶端與服務器端的連接就建立了。客戶端發送數據請求,服務器端接收請求並處理請求,然後把迴應數據發送給客戶端,客戶端讀取數據,最後關閉連接,一次交互結束。

5.udp網絡程序-發送、接收數據

  • 5.1. udp網絡程序-發送數據

    創建一個基於udp的網絡程序流程很簡單,具體步驟如下:

    創建客戶端套接字
    發送/接收數據
    關閉套接字

在這裏插入圖片描述

  • 5.2. udp網絡程序-發送、接收數據的代碼

#coding=utf-8

from socket import *

# 1. 創建udp套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)

# 2. 準備接收方的地址
dest_addr = ('192.168.236.129', 8080)

# 3. 從鍵盤獲取數據
send_data = input("請輸入要發送的數據:")

# 4. 發送數據到指定的電腦上
udp_socket.sendto(send_data.encode('utf-8'), dest_addr)

# 5. 等待接收對方發送的數據
recv_data = udp_socket.recvfrom(1024)  # 1024表示本次接收的最大字節數

# 6. 顯示對方發送的數據
# 接收到的數據recv_data是一個元組
# 第1個元素是對方發送的數據
# 第2個元素是對方的ip和端口
print(recv_data[0].decode('gbk'))
print(recv_data[1])

# 7. 關閉套接字
udp_socket.close()
  • 5.3 python3編碼轉換

    在收發數據的過程中,是需要對收到的數據進行解碼的
    decode(encoding=“utf-8”, errors=“strict”)編碼
    encode(encoding=“utf-8”, errors=“strict”)解碼
  • 5.4 udp綁定信息

    • 5.4.1udp網絡程序-端口問題

      • 會變的端口號
      • 重新運行多次腳本,然後在“網絡調試助手”中,看到的現象如下:
        -在這裏插入圖片描述
        • 每重新運行一次網絡程序,上圖中紅圈中的數字,不一樣的原因在於,這個數字標識這個網絡程序,當重新運行時,如果沒有確定到底用哪個,系統默認會隨機分配
        • 記住一點:這個網絡程序在運行的過程中,這個就唯一標識這個程序,所以如果其他電腦上的網絡程序如果想要向此程序發送數據,那麼就需要向這個數字(即端口)標識的程序發送即可
    • 5.4.2. udp綁定信息

      • <1>. 綁定信息
        一般情況下,在一臺電腦上運行的網絡程序有很多,爲了不與其他的網絡程序佔用同一個端口號,往往在編程中,udp的端口號一般不綁定

      • 但是如果需要做成一個服務器端的程序的話,是需要綁定的,想想看這又是爲什麼呢?

      • 如果報警電話每天都在變,想必世界就會亂了,所以一般服務性的程序,往往需要一個固定的端口號,這就是所謂的端口綁定

      • <2>. 綁定示例

#coding=utf-8

from socket import *

# 1. 創建套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)

# 2. 綁定本地的相關信息,如果一個網絡程序不綁定,則系統會隨機分配
local_addr = ('', 7788) #  ip地址和端口號,ip一般不用寫,表示本機的任何一個ip
udp_socket.bind(local_addr)

# 3. 等待接收對方發送的數據
recv_data = udp_socket.recvfrom(1024) #  1024表示本次接收的最大字節數

# 4. 顯示接收到的數據
print(recv_data[0].decode('gbk'))

# 5. 關閉套接字
udp_socket.close()`- 
  • <3>. 總結
    一個udp網絡程序,可以不綁定,此時操作系統會隨機進行分配一個端口,如果重新運行此程序端口可能會發生變化
    一個udp網絡程序,也可以綁定信息(ip地址,端口號),如果綁定成功,那麼操作系統用這個端口號來進行區別收到的網絡數據是否是此進程的
  • 貢獻出我寫的簡易的udp聊天器
import socket


def send_msg(udp_socket):
    """獲取鍵盤數據,並將其發送給對方"""
    # 1. 從鍵盤輸入數據
    msg = input("\n請輸入要發送的數據:")
    # 2. 輸入對方的ip地址
    dest_ip = input("\n請輸入對方的ip地址:")
    # 3. 輸入對方的port
    dest_port = int(input("\n請輸入對方的port:"))
    # 4. 發送數據
    udp_socket.sendto(msg.encode("utf-8"), (dest_ip, dest_port))


def recv_msg(udp_socket):
    """接收數據並顯示"""
    # 1. 接收數據
    recv_msg = udp_socket.recvfrom(1024)
    # 2. 解碼
    recv_ip = recv_msg[1]
    recv_msg = recv_msg[0].decode("utf-8")
    # 3. 顯示接收到的數據
    print(">>>%s:%s" % (str(recv_ip), recv_msg))


def main():
    # 1. 創建套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 2. 綁定本地信息
    udp_socket.bind(("", 7890))
    while True:
        # 3. 選擇功能
        print("="*30)
        print("1:發送消息")
        print("2:接收消息")
        print("="*30)
        op_num = input("請輸入要操作的功能序號:")

        # 4. 根據選擇調用相應的函數
        if op_num == "1":
            send_msg(udp_socket)
        elif op_num == "2":
            recv_msg(udp_socket)
        else:
            print("輸入有誤,請重新輸入...")

if __name__ == "__main__":
    main()`
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章