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

 

1、udp簡介

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

 

2、udp特色:

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

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

 

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

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

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

代碼以下:windows

#coding=utf-8
from socket import *

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

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

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

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

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

運行程序:服務器

這個時候我就向個人另一臺IP地址爲:192.168.100.101 端口號爲8080的程序發送了「我是侯哥」這一條消息。咱們藉助於網絡調試助手軟件用於測試,網絡調試助手各個平臺的系統都有,你們能夠本身下載使用。網絡

說明:個人代碼是在windows電腦上運行的,個人網絡調試助手是在Mac電腦上運行的,若是沒有兩臺電腦的,也可使用虛擬機測試。多線程

 

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

#coding=utf-8
from socket import *

#一、建立socket套接字
udpSocket = socket(AF_INET,SOCK_DGRAM)

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

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

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

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

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

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

運行程序:併發

 

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

會變的端口號:從新運行屢次腳本,而後在「網絡調試助手」中,看到的現象以下:app

說明:socket

  • 每從新運行一次網絡程序,上圖中紅圈中的數字,不同的緣由在於,這個數字標識這個網絡程序,當從新運行時,若是沒有肯定到底用哪一個,系統默認會隨機分配
  • 記住一點:這個網絡程序在運行的過程當中,這個就惟一標識這個程序,因此若是其餘電腦上的網絡程序若是想要向此程序發送數據,那麼就須要向這個數字(即端口)標識的程序發送便可

 

6、udp綁定信息

通常狀況下,在一天電腦上運行的網絡程序有不少,而各自用的端口號不少狀況下不知道,爲了避免與其餘的網絡程序佔用同一個端口號,每每在編程中,udp的端口號通常不綁定,可是若是須要作成一個服務器端的程序的話,是須要綁定的。就像報警電話天天都在變,想必世界就會亂了,因此通常服務性的程序,每每須要一個固定的端口號,這就是所謂的端口綁定tcp

綁定示例

#coding=utf-8
from socket import *

#一、建立socket套接字
udpSocket = socket(AF_INET,SOCK_DGRAM)

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

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

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

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

windows電腦發送信息

mac電腦接收信息以下:

說明:

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

 

7、udp網絡通訊過程

 

8、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的聊天功能。

9、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上運行程序

相關文章
相關標籤/搜索