(一)wireshark抓包工具的使用web
首先,咱們要安裝一個wireshark,他是一個抓包工具,方便咱們後面學習下載傳送的驗證,網上能夠很方便下載到,這裏再也不贅述。一下是其使用方法:編程
以上就是wireshark的基本使用方法。安全
(二)應用:TFTP客戶端服務器
TFTP(Trivial File Transfer Protocol,簡單文件傳輸協議)網絡
是TCP/IP協議族中的一個用來在客戶端與服務器之間進行簡單文件傳輸的協議socket
特色:tcp
TFTP服務器默認監聽69號端口工具
當客戶端發送「下載」請求(即讀請求)時,須要向服務器的69端口發送學習
服務器若批准此請求,則使用一個新的、臨時的端口進行數據傳輸spa
當服務器找到須要發送的文件後,會馬上打開文件,把文件中的數據經過TFTP協議發送給客戶端
若是文件的總大小較大(好比3M),那麼服務器分屢次發送,每次會從文件中讀取512個字節的數據發送過來
由於發送的次數有可能會不少,因此爲了讓客戶端對接收到的數據進行排序,因此在服務器發送那512個字節數據的時候,會多發2個字節的數據,用來存放序號,而且放在512個字節數據的前面,序號是從1開始的
由於須要從服務器上下載文件時,文件可能不存在,那麼此時服務器就會發送一個錯誤的信息過來,爲了區分服務發送的是文件內容仍是錯誤的提示信息,因此又用了2個字節 來表示這個數據包的功能(稱爲操做碼),而且在序號的前面。
如下爲其操做碼:
由於udp的數據包不安全,即發送方發送是否成功不能肯定,因此TFTP協議中規定,爲了讓服務器知道客戶端已經接收到了剛剛發送的那個數據包,因此當客戶端接收到一個數據包的時候須要向服務器進行發送確認信息,即發送收到了,這樣的包成爲ACK(應答包)
爲了標記數據已經發送完畢,因此規定,當客戶端接收到的數據小於516(2字節操做碼+2個字節的序號+512字節數據)時,就意味着服務器發送完畢了
因此,TFTP數據包的格式以下:
3.參考代碼
1 # -*- coding:utf-8 -*- 2 3 import struct 4 from socket import * 5 import time 6 import os 7 8 def main(): 9 10 11 #0. 獲取要下載的文件名字: 12 downloadFileName = raw_input("請輸入要下載的文件名:") 13 14 #1.建立socket 15 udpSocket = socket(AF_INET, SOCK_DGRAM) 16 17 requestFileData = struct.pack("!H%dsb5sb"%len(downloadFileName), 1, downloadFileName, 0, "octet", 0) 18 19 #2. 發送下載文件的請求 20 udpSocket.sendto(requestFileData, ("192.168.119.215", 69)) 21 22 flag = True #表示可以下載數據,即不擅長,若是是false那麼就刪除 23 num = 0 24 f = open(downloadFileName, "w") 25 26 while True: 27 #3. 接收服務發送回來的應答數據 28 responseData = udpSocket.recvfrom(1024) 29 30 # print(responseData) 31 recvData, serverInfo = responseData 32 33 opNum = struct.unpack("!H", recvData[:2]) 34 35 packetNum = struct.unpack("!H", recvData[2:4]) 36 37 print(packetNum[0]) 38 39 # print("opNum=%d"%opNum) 40 # print(opNum) 41 42 # if 若是服務器發送過來的是文件的內容的話: 43 if opNum[0] == 3: #由於opNum此時是一個元組(3,),因此須要使用下標來提取某個數據 44 45 46 #計算出此次應該接收到的文件的序號值,應該是上一次接收到的值的基礎上+1 47 num = num + 1 48 49 # 若是一個下載的文件特別大,即接收到的數據包編號超過了2個字節的大小 50 # 那麼會從0繼續開始,因此這裏須要判斷,若是超過了65535 那麼就改成0 51 if num==65536: 52 num = 0 53 54 # 判斷此次接收到的數據的包編號是不是 上一次的包編號的下一個 55 # 若是是纔會寫入到文件中,不然不能寫入(由於會重複) 56 if num == packetNum[0]: 57 # 把收到的數據寫入到文件中 58 f.write(recvData[4:]) 59 num = packetNum[0] 60 61 #整理ACK的數據包 62 ackData = struct.pack("!HH", 4, packetNum[0]) 63 udpSocket.sendto(ackData, serverInfo) 64 65 elif opNum[0] == 5: 66 print("sorry,沒有這個文件....") 67 flag = False 68 69 # time.sleep(0.1) 70 71 if len(recvData)<516: 72 break 73 74 if flag == True: 75 f.close() 76 else: 77 os.unlink(downloadFileName)#若是沒有要下載的文件,那麼就須要把剛剛建立的文件進行刪除 78 79 if __name__ == '__main__': 80 main()
(三)udp廣播
網絡編程中的廣播便是發送方只需發送一次數據到中間層而後中間層把它給全部該廣播地址下的接收方。
咱們前面說的對於一段IP地址:192.168.1.X 其中192.168.1.0表示網絡號;192.168.1.255表示廣播號。
1 #coding=utf-8 2 3 import socket, sys 4 5 dest = ('<broadcast>', 7788) #採用<broadcast>這個關鍵字實現通用的廣播地址,就不用特定指定了。 6 7 # 建立udp套接字 8 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 9 10 # 對這個須要發送廣播數據的套接字進行修改設置,不然不能發送廣播數據 11 s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST,1) 12 13 # 以廣播的形式發送數據到本網絡的全部電腦中 14 s.sendto("Hi", dest) 15 16 print "等待對方回覆(按ctrl+c退出)" 17 18 while True: 19 (buf, address) = s.recvfrom(2048) 20 print "Received from %s: %s" % (address, buf)
(四)tcp介紹
tcp:傳輸控制協議
相對udp傳送穩定但速度更慢,目前web服務器廣泛使用tcp。
前面咱們學習了udp協議,在udp通訊模型中,在通訊開始以前,不須要創建相關的連接,只須要發送數據便可,相似於生活中,"寫信"":其過程以下
而在tcp通訊模型中,在通訊開始以前,必定要先創建相關的連接,才能發送數據,相似於生活中,"打電話""。其流程以下:
(五)tcp服務器
若是想讓別人能更夠打通我們的電話獲取相應服務的話,須要作一下幾件事情:
如同上面的電話機過程同樣,在程序中,若是想要完成一個tcp服務器的功能,須要的流程以下:
1 #coding=utf-8 2 from socket import * 3 4 # 建立socket 5 tcpSerSocket = socket(AF_INET, SOCK_STREAM) 6 7 # 綁定本地信息 8 address = ('', 7788) 9 tcpSerSocket.bind(address) 10 11 # 使用socket建立的套接字默認的屬性是主動的,使用listen將其變爲被動的,這樣就能夠接收別人的連接了 12 tcpSerSocket.listen(5) 13 14 # 若是有新的客戶端來連接服務器,那麼就產生一個新的套接字專門爲這個客戶端服務 15 # newSocket用來爲這個客戶端服務 16 # tcpSerSocket就能夠省下來專門等待其餘新客戶端的連接 17 newSocket, clientAddr = tcpSerSocket.accept() 18 19 # 接收對方發送過來的數據,最大接收1024個字節 20 recvData = newSocket.recv(1024) 21 print ('接收到的數據爲:%s'%recvData) 22 23 # 發送一些數據到客戶端 24 newSocket.send("thank you !") 25 26 # 關閉爲這個客戶端服務的套接字,只要關閉了,就意味着爲不能再爲這個客戶端服務了,若是還須要服務,只能再次從新鏈接 27 newSocket.close() 28 29 # 關閉監聽套接字,只要這個套接字關閉了,就意味着整個程序不能再接收任何新的客戶端的鏈接 30 tcpSerSocket.close()
(六)tcp客戶端
所謂的服務器端:就是提供服務的一方,而客戶端,就是須要被服務的一方
tcp的客戶端要比服務器端簡單不少,若是說服務器端是須要本身買手機、查手機卡、設置鈴聲、等待別人打電話流程的話,那麼客戶端就只須要找一個電話亭,拿起電話撥打便可,流程要少不少。
1 from socket import * 2 3 #建立套接字 4 clientSocket = socket(AF_INET, SOCK_STREAM) 5 #進行連接,注意connect參數爲一個元組 6 clientSocket.connect(("192.168.119.153", 8989)) 7 8 #注意: 9 # 1. tcp客戶端已經連接好了服務器,因此在之後的數據發送中,不須要填寫對方的iph和port----->打電話 10 # 2. udp在發送數據的時候,由於沒有以前的連接,所依須要 在每次的發送中 都要填寫接收方的ip和port----->寫信 11 clientSocket.send("haha".encode("gb2312")) 12 13 recvData = clientSocket.recv(1024) 14 15 print("recvData:%s"%recvData) 16 17 clientSocket.close()