網(wǎng)絡(luò)編程3

1.1? udp網(wǎng)絡(luò)程序-發(fā)送數(shù)據(jù)

Socket函數(shù)

mySocket = socket(family, type)

函數(shù)socket()的參數(shù)family用于設(shè)置網(wǎng)絡(luò)通信的域,函數(shù)socket()根據(jù)這個參數(shù)選擇通信協(xié)議的族。通信協(xié)議族在文件sys/socket.h中定義。


函數(shù)socket()的參數(shù)type用于設(shè)置套接字通信的類型,主要有SOCKET_STREAM(流式套接字)、SOCK——DGRAM(數(shù)據(jù)包套接字)等。

并不是所有的協(xié)議族都實現(xiàn)了這些協(xié)議類型,例如,AF_INET協(xié)議族就沒有實現(xiàn)SOCK_SEQPACKET協(xié)議類型。


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

1.創(chuàng)建客戶端套接字

2.發(fā)送/接收數(shù)據(jù)

3.關(guān)閉套接字

代碼如下:

from socket import *

#1.創(chuàng)建套接字

udpSocket = socket(AF_INET, SOCK_DGRAM)

#2.準(zhǔn)備接收方的地址

sendAddr = ('192.168.11.74', 7788)

#3.從鍵盤獲取數(shù)據(jù)

sendData = input("請輸入要發(fā)送的數(shù)據(jù):")

#4.發(fā)送數(shù)據(jù)到指定的電腦上

udpSocket.sendto(sendData.encode('gbk'), sendAddr)

#5.關(guān)閉套接字

udpSocket.close()

1.2 udp網(wǎng)絡(luò)程序-發(fā)送、接收數(shù)據(jù)

#coding=utf-8

fromsocketimport*

#1.創(chuàng)建套接字

udpSocket = socket(AF_INET, SOCK_DGRAM)

#2.準(zhǔn)備接收方的地址

sendAddr = ('192.168.1.103',8080)

#3.從鍵盤獲取數(shù)據(jù)

sendData = input("請輸入要發(fā)送的數(shù)據(jù):")

#4.發(fā)送數(shù)據(jù)到指定的電腦上

udpSocket.sendto(sendData, sendAddr)

#5.等待接收對方發(fā)送的數(shù)據(jù)

recvData = udpSocket.recvfrom(1024)# 1024表示本次接收的最大字節(jié)數(shù)

#6.顯示對方發(fā)送的數(shù)據(jù)

print(recvData)

#7.關(guān)閉套接字

udpSocket.close()

1.3 udp網(wǎng)絡(luò)程序-端口問題

會變的端口號

重新運行多次腳本,然后在“網(wǎng)絡(luò)調(diào)試助手”中,看到的現(xiàn)象如下:


說明:

·每重新運行一次網(wǎng)絡(luò)程序,上圖中紅圈中的數(shù)字,不一樣的原因在于,這個數(shù)字標(biāo)識這個網(wǎng)絡(luò)程序,當(dāng)重新運行時,如果沒有確定到底用哪個,系統(tǒng)默認(rèn)會隨機分配

·記住一點:這個網(wǎng)絡(luò)程序在運行的過程中,這個就唯一標(biāo)識這個程序,所以如果其他電腦上的網(wǎng)絡(luò)程序如果想要向此程序發(fā)送數(shù)據(jù),那么就需要向這個數(shù)字(即端口)標(biāo)識的程序發(fā)送即可

1.4 udp 綁定信息

1.綁定信息

還記得在上一節(jié)課中,如果一個網(wǎng)絡(luò)程序在每次運行的時候端口是隨機變化的么?

一般情況下,在一天電腦上運行的網(wǎng)絡(luò)程序有很多,而各自用的端口號很多情況下不知道,為了不與其他的網(wǎng)絡(luò)程序占用同一個端口號,往往在編程中,udp的端口號一般不綁定

但是如果需要做成一個服務(wù)器端的程序的話,是需要綁定的,想想看這又是為什么呢?

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

2.綁定示例

#coding=utf-8

fromsocketimport*

#1.創(chuàng)建套接字

udpSocket = socket(AF_INET, SOCK_DGRAM)

#2.綁定本地的相關(guān)信息,如果一個網(wǎng)絡(luò)程序不綁定,則系統(tǒng)會隨機分配

bindAddr = ('',7788)# ip地址和端口號,ip一般不用寫,表示本機的任何一個ip

udpSocket.bind(bindAddr)

#3.等待接收對方發(fā)送的數(shù)據(jù)

recvData = udpSocket.recvfrom(1024)# 1024表示本次接收的最大字節(jié)數(shù)

#4.顯示接收到的數(shù)據(jù)

print(recvData)

#5.關(guān)閉套接字

udpSocket.close()

總結(jié)

·一個udp網(wǎng)絡(luò)程序,可以不綁定,此時操作系統(tǒng)會隨機進行分配一個端口,如果重新運行次程序端口可能會發(fā)生變化

·一個udp網(wǎng)絡(luò)程序,也可以綁定信息(ip地址,端口號),如果綁定成功,那么操作系統(tǒng)用這個端口號來進行區(qū)別收到的網(wǎng)絡(luò)數(shù)據(jù)是否是此進程的

1.5 udp網(wǎng)絡(luò)通信過程


1.6 udp應(yīng)用:echo服務(wù)器

參考代碼

#coding=utf-8

fromsocketimport*

#1.創(chuàng)建套接字

udpSocket = socket(AF_INET, SOCK_DGRAM)

#2.綁定本地的相關(guān)信息

bindAddr = ('',7788)# ip地址和端口號,ip一般不用寫,表示本機的任何一個ip

udpSocket.bind(bindAddr)

num =1

whileTrue:

#3.等待接收對方發(fā)送的數(shù)據(jù)

recvData = udpSocket.recvfrom(1024)# 1024表示本次接收的最大字節(jié)數(shù)

#4.將接收到的數(shù)據(jù)再發(fā)送給對方

udpSocket.sendto(recvData[0], recvData[1])

#5.統(tǒng)計信息

print('已經(jīng)將接收到的第%d個數(shù)據(jù)返回給對方,內(nèi)容為:%s'%(num,recvData[0]))

num+=1

#5.關(guān)閉套接字

udpSocket.close()

1.7 udp應(yīng)用:聊天室

參考代碼

fromsocketimport*

fromtimeimportctime

#1.創(chuàng)建套接字

udpSocket = socket(AF_INET, SOCK_DGRAM)

#2.綁定本地的相關(guān)信息

bindAddr = ('',7788)# ip地址和端口號,ip一般不用寫,表示本機的任何一個ip

udpSocket.bind(bindAddr)

whileTrue:

#3.等待接收對方發(fā)送的數(shù)據(jù)

recvData = udpSocket.recvfrom(1024)# 1024表示本次接收的最大字節(jié)數(shù)

#4.打印信息

print('【%s】%s:%s'%(ctime(),recvData[1][0],recvData[0]))

#5.關(guān)閉套接字

udpSocket.close()

1.8 udp廣播

網(wǎng)絡(luò)編程中的廣播

importsocket, sys

dest = ('',7788)

#創(chuàng)建udp套接字

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

#對這個需要發(fā)送廣播數(shù)據(jù)的套接字進行修改設(shè)置,否則不能發(fā)送廣播數(shù)據(jù)

s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST,1)

#以廣播的形式發(fā)送數(shù)據(jù)到本網(wǎng)絡(luò)的所有電腦中

s.sendto("Hi", dest)

print("等待對方回復(fù)(按ctrl+c退出)")

whileTrue:

(buf, address) = s.recvfrom(2048)

print("Received from %s: %s"% (address, buf))

1.9 udp總結(jié)

1. udp是TCP/IP協(xié)議族中的一種協(xié)議能夠完成不同機器上的程序間的數(shù)據(jù)通信

2. udp服務(wù)器、客戶端

·udp的服務(wù)器和客戶端的區(qū)分:往往是通過請求服務(wù)和提供服務(wù)來進行區(qū)分

·請求服務(wù)的一方稱為:客戶端

·提供服務(wù)的一方稱為:服務(wù)器

3. udp綁定問題

·一般情況下,服務(wù)器端,需要綁定端口,目的是為了讓其他的客戶端能夠正確發(fā)送到此進程

·客戶端,一般不需要綁定,而是讓操作系統(tǒng)隨機分配,這樣就不會因為需要綁定的端口被占用而導(dǎo)致程序無法運行的情況

1.10 udp模擬qq

1.任務(wù)要求:

·使用多線程完成一個全雙工的QQ聊天程序

單工、半雙工、全雙工

單工數(shù)據(jù)傳輸只支持?jǐn)?shù)據(jù)在一個方向上傳輸;

半雙工數(shù)據(jù)傳輸允許數(shù)據(jù)在兩個方向上傳輸,但是,在某一時刻,只允許數(shù)據(jù)在一個方向上傳輸,它實際上是一種切換方向的單工通信;

全雙工數(shù)據(jù)通信允許數(shù)據(jù)同時在兩個方向上傳輸,因此,全雙工通信是兩個單工通信方式的結(jié)合,它要求發(fā)送設(shè)備和接收設(shè)備都有獨立的接收和發(fā)送能力.

2.參考代碼

from threading import Thread

from socket import *

# 1.收數(shù)據(jù),然后打印

def recvData():

while True:

recvInfo = udpSocket.recvfrom(1024)

print(">>%s:%s" % (str(recvInfo[1]), recvInfo[0]))

# 2.檢測鍵盤,發(fā)數(shù)據(jù)

def sendData():

while True:

sendInfo = input("<<")

udpSocket.sendto(sendInfo.encode("gb2312"), (destIp, destPort))

udpSocket = None

destIp = ""

destPort = 0

def main():

global udpSocket

global destIp

global destPort

destIp = input("對方的ip:")

destPort = int(input("對方的ip:"))

udpSocket = socket(AF_INET, SOCK_DGRAM)

udpSocket.bind(("", 4567))

tr = Thread(target=recvData)

ts = Thread(target=sendData)

tr.start()

ts.start()

tr.join()

ts.join()

if __name__ == "__main__":

main()

1.11 TFTP客戶端

1. TFTP協(xié)議介紹

TFTP(Trivial File Transfer Protocol,簡單文件傳輸協(xié)議)

是TCP/IP協(xié)議族中的一個用來在客戶端與服務(wù)器之間進行簡單文件傳輸?shù)膮f(xié)議

特點:

·簡單

·占用資源小

·適合傳遞小文件

·適合在局域網(wǎng)進行傳遞

·端口號為69

·基于UDP實現(xiàn)

2. TFTP下載過程

TFTP服務(wù)器默認(rèn)監(jiān)聽69號端口

當(dāng)客戶端發(fā)送“下載”請求(即讀請求)時,需要向服務(wù)器的69端口發(fā)送

服務(wù)器若批準(zhǔn)此請求,則使用一個新的、臨時的 端口進行數(shù)據(jù)傳輸


當(dāng)服務(wù)器找到需要現(xiàn)在的文件后,會立刻打開文件,把文件中的數(shù)據(jù)通過TFTP協(xié)議發(fā)送給客戶端

如果文件的總大小較大(比如3M),那么服務(wù)器分多次發(fā)送,每次會從文件中讀取512個字節(jié)的數(shù)據(jù)發(fā)送過來

因為發(fā)送的次數(shù)有可能會很多,所以為了讓客戶端對接收到的數(shù)據(jù)進行排序,所以在服務(wù)器發(fā)送那512個字節(jié)數(shù)據(jù)的時候,會多發(fā)2個字節(jié)的數(shù)據(jù),用來存放序號,并且放在512個字節(jié)數(shù)據(jù)的前面,序號是從1開始的

因為需要從服務(wù)器上下載文件時,文件可能不存在,那么此時服務(wù)器就會發(fā)送一個錯誤的信息過來,為了區(qū)分服務(wù)發(fā)送的是文件內(nèi)容還是錯誤的提示信息,所以又用了2個字節(jié) 來表示這個數(shù)據(jù)包的功能(稱為操作碼),并且在序號的前面


因為udp的數(shù)據(jù)包不安全,即發(fā)送方發(fā)送是否成功不能確定,所以TFTP協(xié)議中規(guī)定,為了讓服務(wù)器知道客戶端已經(jīng)接收到了剛剛發(fā)送的那個數(shù)據(jù)包,所以當(dāng)客戶端接收到一個數(shù)據(jù)包的時候需要向服務(wù)器進行發(fā)送確認(rèn)信息,即發(fā)送收到了,這樣的包成為ACK(應(yīng)答包)

為了標(biāo)記數(shù)據(jù)已經(jīng)發(fā)送完畢,所以規(guī)定,當(dāng)客戶端接收到的數(shù)據(jù)小于516(2字節(jié)操作碼+2個字節(jié)的序號+512字節(jié)數(shù)據(jù))時,就意味著服務(wù)器發(fā)送完畢了

TFTP數(shù)據(jù)包的格式如下:


?O4;3?m

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、概念 首先,理清一些概念 TCP/IP和UDP,HTTP協(xié)議,Socket 1.TCP/IP和UDP,是網(wǎng)絡(luò)中...
    _AJH閱讀 4,433評論 0 18
  • tcp/ip簡介 為了把全世界的所有不同類型的計算機都連接起來,就必須規(guī)定一套全球通用的協(xié)議,為了實現(xiàn)互聯(lián)網(wǎng)這個目...
    盛夏光年_49e9閱讀 591評論 0 0
  • 一 、Socket 網(wǎng)絡(luò)上的兩個程序通過一個雙向的通信連接實現(xiàn)數(shù)據(jù)的交換,這個連接的一端稱為一個 Socket。S...
    空白Null閱讀 1,891評論 1 9
  • 1. G和J 當(dāng)大家發(fā)G的讀音時,會發(fā)現(xiàn)讀音的末尾是發(fā)ei的音,這也不難理解,因為B/be/ 、C/se/、D/d...
    yoku醬閱讀 289評論 0 2
  • Mysql 內(nèi)存+后臺線程 主從復(fù)制 1. Master 庫中,數(shù)據(jù)變更時,寫入binary Log。 2. Sl...
    郭大瞎閱讀 213評論 0 0

友情鏈接更多精彩內(nèi)容