本篇包括網絡編程概述、UDP簡介、TFTP簡介、TCP編程等。
目錄
一、tcp/ip協議簡介
二、端口
三、IP地址
四、mac地址
五、socket簡介
六、UDP網絡通信過程
七、模擬QQ聊天-多線程實現
八、wireshark抓包工具的使用
九、tftp下載器的使用(tftpd64或tftpd32)
十、UDP廣播
十一、TCP服務器、客戶端簡介及實現
11.1 TCP簡介
11.2 TCP和UDP通信模型
11.3 Python實現tcp服務器和客戶端
一、tcp/ip協議簡介
tcp/ip不是兩個協議,而是一個協議組,實際為4層,邏輯上可以為7層,如下圖所示:
二、端口
為什么使用端口?只有ip地址時只知道發往哪個電腦而不知道發往哪個程序,端口用來辨識要發往的具體程序。
為什么不用PID辨識進程?因為進程是動態的,遠端電腦可能不知道本地的pid號。
知名端口:大家都知道的約定好的端口,如80端口為HTTP服務,21端口為FTP服務,范圍為0~1023。
動態端口:用戶自己定義的端口,范圍為1024~65535.
查看端口命令:
注意:在同一個OS中,端口不允許相同,如果某個端口已經被使用了,那么在這個進程釋放這個端口之前,其他進程不能使用這個端口。因為端口用來區分一個進程。 三、IP地址 用來邏輯上表示網絡上的唯一一臺電腦。 注意:一個電腦可以有多個網卡,即多個IP地址! IP地址分類 其中網絡號固定不變,表示位于同一網絡中的電腦,主機號為當前網絡中的電腦號。 主機號為0時表示網段號,主機號為255時為網關。 D類用于多播(不是廣播),例如視頻會議,只有一些人可以看到。 E類實驗和開發用。 私有ip 用于局域網中,訪問公網時不能使用,需要轉換為公有ip訪問外網。范圍如下: 注意 IP地址127.0.0.1~127.255.255.255用于回路測試,即測試當前電腦tcp/ip協議能不能用,例如ping 127.0.0.1,即使拔掉網線也能ping得通。 四、MAC地址 網卡的序列號,形如XX:XX:XX:XX:XX:XX,六組十六進制數,前三組表示廠商序列號,后三組表示網卡序列號。 五、socket簡介 socket:通過網絡使進程間通信。 注意:一個進程可以有多個socket! python測試程序如下: 端口綁定(只能綁定自己的端口!) 上面程序每次運行時操作系統為它分配的端口不一樣,這導致了遠端電腦不知道每次運行的端口,不能發送信息到本地。 python程序如下: 注意:bindAddr中第一個參數為空,因為該參數表示本地IP地址,但本地可能有多個IP,空表示任意ip都進行綁定。 六、UDP網絡通信過程 應用層填寫需要發送的數據;傳輸增加上端口號等;網絡層加上目的ip等;鏈路層加上目的mac等;如下圖: 七、模擬QQ聊天-多線程實現 全雙工實現QQ聊天,代碼如下: from threading import Thread from socket import * #1. 收數據,然后打印 def recvData(): while True: recvInfo = udpSocket.recvfrom(1024) print(">>%s:%s"%(str(recvInfo[1]), recvInfo[0])) #2. 檢測鍵盤,發數據 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() 八、wireshark抓包工具的使用 wireshark工具可以抓取當前電腦中所有網絡數據,具體如圖所示: 九、tftp下載器的使用(tftpd64或tftpd32) tftp是tcp/ip協議族中用來將客戶端和服務器之間進行簡單文件傳輸的協議。 特點如下: 基于UDP實現,可能會丟包,實現過程為收到-回復,下載過程如下: TFTP數據表格式如下: 讀寫請求格式:操作碼為1或2,分別表示讀或寫;文件名為文件名稱;0為固定寫法;模式有幾種,最常用的為octet;最后跟一個0。 數據表格式:操作碼固定為3;文件名為文件名稱;塊編號為文件分割的塊編號;數據為詳細數據。 確認格式:操作碼固定為4;塊編號為確認收到的文件分塊編號。 錯誤表格式:操作碼固定為5;差錯碼為固定好的錯誤編號;后面接具體差錯信息;最后跟一個0; 注意:確認包發往的是服務器發送本地進程時分配的隨機端口! 怎樣確定數據已經發送完畢了? 規定, 當客戶端接收到的數據?于516(2字節操作碼+2個字節的序號+512字節數據) 時, 就意味著服務器發送完畢了。 怎樣保證包中每個碼的字節數? python中組包代碼如下: !:表示網絡中的數據,網絡中的數據用大端表示。 H:占用2個字節,對應后面的1。 8s:占用8個字節,對應后面的"test.jpg"。 b:占用1個字節,對應后面的0。 5s:占用5個字節,對應后面的"octet"。 b:占用1個字節,對應后面的0。 表格式如圖所示: 使用python從tftp服務器中下載文件 1)首先啟動tftpd64應用程序,設置好下載的目錄和ip地址。 2)python代碼如下: # -*- coding:utf-8 -*- import struct from socket import * import time import os def main(): #0. 獲取要下載的文件名字: downloadFileName = raw_input("請輸入要下載的文件名:") #1.創建socket udpSocket = socket(AF_INET, SOCK_DGRAM) requestFileData = struct.pack("!H%dsb5sb"%len(downloadFileName), 1, downloadFileName, 0, "octet", 0) #2. 發送下載文件的請求 udpSocket.sendto(requestFileData, ("192.168.119.215", 69)) flag = True #表示能夠下載數據,即不擅長,如果是false那么就刪除 num = 0 f = open(downloadFileName, "w") while True: #3. 接收服務發送回來的應答數據 responseData = udpSocket.recvfrom(1024) # print(responseData) recvData, serverInfo = responseData opNum = struct.unpack("!H", recvData[:2]) packetNum = struct.unpack("!H", recvData[2:4]) print(packetNum[0]) # print("opNum=%d"%opNum) # print(opNum) # if 如果服務器發送過來的是文件的內容的話: if opNum[0] == 3: #因為opNum此時是一個元組(3,),所以需要使用下標來提取某個數據 #計算出這次應該接收到的文件的序號值,應該是上一次接收到的值的基礎上+1 num = num + 1 # 如果一個下載的文件特別大,即接收到的數據包編號超過了2個字節的大小 # 那么會從0繼續開始,所以這里需要判斷,如果超過了65535 那么就改為0 if num==65536: num = 0 # 判斷這次接收到的數據的包編號是否是 上一次的包編號的下一個 # 如果是才會寫入到文件中,否則不能寫入(因為會重復) if num == packetNum[0]: # 把收到的數據寫入到文件中 f.write(recvData[4:]) num = packetNum[0] #整理ACK的數據包 ackData = struct.pack("!HH", 4, packetNum[0]) udpSocket.sendto(ackData, serverInfo) elif opNum[0] == 5: print("sorry,沒有這個文件....") flag = False # time.sleep(0.1) if len(recvData)<516: break if flag == True: f.close() else: os.unlink(downloadFileName)#如果沒有要下載的文件,那么就需要把剛剛創建的文件進行刪除 if __name__ == '__main__': main() 十、UDP廣播 UDP廣播不是對每個用戶輪流發送數據,而是發送到交換機,交換機負責同時發送給每個用戶。 廣播可用于動態獲取ip地址。 單播----點對點;多播----一對多;廣播----一無所有。 注意:廣播只用于UDP中,TCP不能廣播! python簡單實現: 十一、TCP服務器、客戶端簡介及實現 11.1 TCP簡介 tcp:傳輸控制協議 特點:1、穩定;2、相對udp而言要慢一些;3、web服務器都是使用的tcp; udp:用戶數據包協議 特點:1、不穩定;2、相對tcp而言要快一些; 11.2 TCP和UDP通信模型 udp通信模型:相當于寫信; tcp通信模型:相當于打電話; socket創建出來的套接字,默認為主動套接字,即發送數據給別人。listen()將主動套接字變為被動套接字。 TCP服務器端: 1、買個手機 socket(xxx); 2、插入手機卡 bind(xxx); 3、設置手機為響鈴模式 listen(); 4、等待別人的電話,準備好接聽 accept(); TCP客戶端: 1、買個手機 socket(xxx); 2、撥打電話 connect(xxx); 11.3 python實現tcp服務器和客戶端 tcp服務器端實現(簡單原理實現,非實際的多進程)如下: 注意: accept用來接收客戶端請求,并重新創建一個socket為新的客戶服務,然后等待下一個客戶端的請求。 clientSocket用來專門為新的客戶端服務。 代碼解釋: 第一個while循環用來監聽是否有新客戶接入,并為它分配服務資源。 第二個while循環為新的客戶端服務。注意:當客戶端下線時,newSocket.recv(1024)這句可以解阻塞,且返回值為0,從而可以跳出循環。 該程序為單任務,實際服務器為多進程實現,只需將第二個while定義為一個函數,在第一個while中啟動一個進程執行該函數即可。 #coding=utf-8 from socket import * # 創建socket tcpSerSocket = socket(AF_INET, SOCK_STREAM) # 綁定本地信息 address = ('', 7788) tcpSerSocket.bind(address) # 使?socket創建的套接字默認的屬性是主動的, 使?listen將其變為被動的, 這樣就可以接收。 # 5表示服務器同一時刻最多允許5個客戶端發數據 tcpSerSocket.listen(5) while True: # 如果有新的客戶端來連接服務器, 那么就產??個新的套接字專?為這個客戶端服務器 # newSocket?來為這個客戶端服務 # tcpSerSocket就可以省下來專?等待其他新客戶端的鏈接 newSocket, clientAddr = tcpSerSocket.accept() # 該循環為新的客戶端服務。注意:當客戶端下線時,newSocket.recv(1024)這句可以解阻塞,且返回 # 值為0,從而可以跳出循環 while True: # 接收對?發送過來的數據, 最?接收1024個字節 recvData = newSocket.recv(1024) # 如果接收的數據的?度為0, 則意味著客戶端關閉了鏈接 if len(recvData)>0: print 'recv:',recvData else: break # 發送?些數據到客戶端 sendData = raw_input("send:") newSocket.send(sendData) # 關閉為這個客戶端服務的套接字, 只要關閉了, 就意味著為不能再為這個客戶端服務了 newSocket.close() # 關閉監聽套接字, 只要這個套接字關閉了, 就意味著整個程序不能再接收任何新的客戶端的連接 tcpSerSocket.close() tcp客戶器端實現如下: from socket import * #創建TCP套接字 clientSocket = socket(AF_INET, SOCK_STREAM) #鏈接服務器 clientSocket.connect(("192.168.119.153", 8989)) #注意: # 1. tcp客戶端已經連接好了服務器,所以在以后的數據發送中,不需要填寫對方的iph和port----->打電話 # 2. udp在發送數據的時候,因為沒有之前的鏈接,所以需要 在每次的發送中 都要填寫接收方的ip和port----->寫信 #發送數據 clientSocket.send("haha".encode("gb2312")) #接收數據 recvData = clientSocket.recv(1024) #打印接收到的數據 print("recvData:%s"%recvData) #關閉客戶端socket clientSocket.close()linux服務器開發學習視頻資料,包括Linux,Nginx,ZeroMQ,MySQL,redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK等等。
需要知識技術學習視頻文檔資料的朋友可以后臺私信【架構】獲取