python網絡-Socket之udp編程(24)


 

一、udp簡介

  • udp --- 用戶數據報協議,是一個無連接的簡單的面向數據報的運輸層協議。
  • udp不提供可靠性,它只是把應用程序傳給IP層的數據報發送出去,但是並不能保證它們能到達目的地。
  • udp在傳輸數據報前不用在客戶和服務器之間建立一個連接,且沒有超時重發等機制,故而傳輸速度很快。
  • udp是一種面向無連接的協議,每個數據報都是一個獨立的信息,包括完整的源地址或目的地址,它在網絡上以任何可能的路徑傳往目的地,因此能否到達目的地,到達目的地的時間以及內容的正確性都是不能被保證的。

 

二、udp特點:

udp是面向無連接的通訊協議,udp數據包括目的端口號和源端口號信息,由於通訊不需要連接,所以可以實現廣播發送。 udp傳輸數據時有大小限制,每個被傳輸的數據報必須限定在64KB之內。 udp是一個不可靠的協議,發送方所發送的數據報並不一定以相同的次序到達接收方。udp是面向消息的協議,通信時不需要建立連接,數據的傳輸自然是不可靠的,udp一般用於多點通信和實時的數據業務,比如:

  • 語音廣播
  • TFTP(簡單文件傳送)
  • SNMP(簡單網絡管理協議)
  • RIP(路由信息協議,如報告股票市場,航空信息)
  • DNS(域名解釋)

 

三、udp網絡程序-發送數據

創建一個udp客戶端程序的流程是簡單,具體步驟如下:

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

代碼如下:

#coding=utf-8
from socket import *

#1、創建socket套接字
#socket(參數1,參數2)
#參數1 = AF_INET固定的
#參數2 = SOCK_DGRAM表示udp,上篇文章中說過SOCK_STREM表示tcp
udpSocket = socket(AF_INET,SOCK_DGRAM)

#2、准備接收方的地址
sendAddress = ("192.168.100.101",8080)

#3、從鍵盤輸入需要發送的數據
sendData = input("請輸入要發送的數據:")

#4、發送數據到指定電腦
udpSocket.sendto(sendData.encode(),sendAddress)

#5、關閉socket套接字
udpSocket.close()

運行程序:

這個時候我就向我的另外一台IP地址為:192.168.100.101 端口號為8080的程序發送了“我是侯哥”這一條消息。我們借助於網絡調試助手軟件用於測試,網絡調試助手各個平台的系統都有,大家可以自己下載使用。

說明:我的代碼是在windows電腦上運行的,我的網絡調試助手是在Mac電腦上運行的,如果沒有兩台電腦的,也可以使用虛擬機測試。

 

四、udp網絡程序-接收數據

#coding=utf-8
from socket import *

#1、創建socket套接字
udpSocket = socket(AF_INET,SOCK_DGRAM)

#2、准備接收方的地址
sendAddress = ("192.168.100.101",8080)

#3、從鍵盤輸入需要發送的數據
sendData = input("請輸入要發送的數據:")

#4、發送數據到指定電腦
udpSocket.sendto(sendData.encode(),sendAddress)

#5、等待接收對方發送的數據
receiveData = udpSocket.recvfrom(1024)

#6、顯示對方發送的數據
print(receiveData)

#7、關閉socket套接字
udpSocket.close()

運行程序:

 

五、udp網絡程序-端口問題

會變的端口號:重新運行多次腳本,然后在“網絡調試助手”中,看到的現象如下:

說明:

  • 每重新運行一次網絡程序,上圖中紅圈中的數字,不一樣的原因在於,這個數字標識這個網絡程序,當重新運行時,如果沒有確定到底用哪個,系統默認會隨機分配
  • 記住一點:這個網絡程序在運行的過程中,這個就唯一標識這個程序,所以如果其他電腦上的網絡程序如果想要向此程序發送數據,那么就需要向這個數字(即端口)標識的程序發送即可

 

六、udp綁定信息

一般情況下,在一天電腦上運行的網絡程序有很多,而各自用的端口號很多情況下不知道,為了不與其他的網絡程序占用同一個端口號,往往在編程中,udp的端口號一般不綁定,但是如果需要做成一個服務器端的程序的話,是需要綁定的。就像報警電話每天都在變,想必世界就會亂了,所以一般服務性的程序,往往需要一個固定的端口號,這就是所謂的端口綁定

綁定示例

#coding=utf-8
from socket import *

#1、創建socket套接字
udpSocket = socket(AF_INET,SOCK_DGRAM)

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

#3、等待接收方發送消息
receiveData = udpSocket.recvfrom(1024)

#4、顯示對方發送的數據
print(receiveData)

#5、關閉socket套接字
udpSocket.close()

windows電腦發送信息

mac電腦接收信息如下:

說明:

  • 一個udp網絡程序,可以不綁定,此時操作系統會隨機進行分配一個端口,如果重新運行次程序端口可能會發生變化
  • 一個udp網絡程序,也可以綁定信息(ip地址,端口號),如果綁定成功,那么操作系統用這個端口號來進行區別收到的網絡數據是否是此進程的

 

七、udp網絡通信過程

 

八、udp應用:多線程對話聊天實現

#coding=utf-8
from threading import Thread
from socket import *

#接收數據
def receiveInfo():
    while True:
        receiveData = udpSocket.recvfrom(1024)
        print("<<%s:%s"%(str(receiveData[1]),str(receiveData[0])))

#發送數據
def sendInfo():
    while True:
        sendData = input("")
        udpSocket.sendto(sendData.encode("gb2312"),(destIp,destPort))

udpSocket = None
destIp = ""
destPort = 0

def main():
    global udpSocket
    global destIp
    global destPort

    destIp = input("對方的IP:")
    destPort = int(input("對方的Port:"))

    udpSocket = socket(AF_INET,SOCK_DGRAM)
    udpSocket.bind(("",4567))#這里寫兩個()的原因是將("",4567)當做一個整體元組使用

    tr = Thread(target = receiveInfo)
    ts = Thread(target = sendInfo)

    tr.start()
    ts.start()

    tr.join()
    ts.join()

if __name__ == '__main__':
    main()

Mac電腦上執行程序如下:

windows電腦上運行網絡調試助手如下:

從而就是實現了基於socket的udp的聊天功能。

九、udp應用:多線程聊天室的實現

程序基本流程:創建接收端socket ---> 創建發送到socket ---> 啟動接收端socket ---> 啟動發送端socket ---> 等待用戶輸入 ---> 接收用戶輸入並發送到廣播 ---> 接收信息並顯示。

# -*- coding:utf-8 -*-
from socket import *
from time import ctime, sleep
import threading

class ChatRoomPlus:
    def __init__(self):
        # 全局參數配置
        self.encoding = "utf-8"  # 使用的編碼方式
        self.broadcastPort = 7788   # 廣播端口

        # 創建廣播接收器
        self.recvSocket = socket(AF_INET, SOCK_DGRAM)
        self.recvSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        self.recvSocket.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
        self.recvSocket.bind(('', self.broadcastPort))

        # 創建廣播發送器
        self.sendSocket = socket(AF_INET, SOCK_DGRAM)
        self.sendSocket.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)

        # 其他
        self.threads = []

    def send(self):
        """發送廣播"""

        print("UDP發送器啟動成功...")
        self.sendSocket.sendto("***加入了聊天室".encode(self.encoding), ('255.255.255.255', self.broadcastPort))
        while True:
            sendData = input("請輸入需要發送的消息:")

            self.sendSocket.sendto(sendData.encode(self.encoding), ('255.255.255.255', self.broadcastPort))
            # print("【%s】%s:%s" % (ctime(), "我", sendData))

            sleep(1)

    def recv(self):
        """接收廣播"""

        print("UDP接收器啟動成功...")
        while True:
            # 接收數據格式:(data, (ip, port))
            recvData = self.recvSocket.recvfrom(1024)

            print("【%s】[%s : %s] : %s" % (ctime(), recvData[1][0], recvData[1][1], recvData[0].decode(self.encoding)))

            sleep(1)

    def start(self):
        """啟動線程"""

        t1 = threading.Thread(target=self.recv)
        t2 = threading.Thread(target=self.send)
        self.threads.append(t1)
        self.threads.append(t2)

        for t in self.threads:
            t.setDaemon(True)
            t.start()

        while True:
            pass


if __name__ == "__main__":
    demo = ChatRoomPlus()
    demo.start()

運行效果:

Mac電腦上運行

linux電腦上運行程序

windows上運行程序


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM