網絡編程Socket,神級程序員說通過這一篇文章讓你基本掌握!

網絡編程

定義:所為網絡編程即是對信息的發送和接收。在給大家分享之前呢,我介紹一下我弄的一個學習交流群,有什麼不懂的問題,都可以在群裡踴躍發言,需要啥資料隨時在群文件裡面獲取自己想要的資料。這個python群就是:330637182 小編期待大家一起進群交流討論,講實話還是一個非常適合學習的地方的。各種入門資料啊,進階資料啊,框架資料啊 爬蟲等等,都是有的,風裡雨裡,小編都在群裡等你。

網絡編程Socket,神級程序員說通過這一篇文章讓你基本掌握!

主要工作:

(1)發送端:將信息以規定的協議組裝成數據包。

(2)接收端:對收到的數據包解析,以提取所需要的信息。

Socket:兩個在網絡上的程序通過一個雙向的通信連接,實現數據的交換,此連接的一端稱為一個socket。

Socket的本質:Socket是一個編程接口(API),TCP/IP協議需要向開發者提供做網絡開發用的接口,這就是Socket接口,它是對TCP/IP協議網絡通信的封裝。

python中用有標準庫socket,要進行socket編程,只需導入這個模塊即可。

例一(實現一個單對單,只能發送一次消息的一次性服務端和客戶端):

1 #服務端2 import socket 34 address = ("localhost", 6666) #寫明服務端要監聽的地址,和端口號5 server = socket.socket() #生成一個socket對象6 server.bind(address) #用socket對象綁定要監聽的地址和端口7 server.listen() #開始監聽89 conn,addr = server.accept() #等帶新連接接入服務端,返回一個新的socket對象和地址,地址格式同前面格式10 '''11 Wait for an incoming connection. Return a new socket12 representing the connection, and the address of the client.13 '''14 data = conn.recv(1024) #接收信息,寫明要接收信息的最大容量,單位為字節15 print("server recv:", data)16 conn.send(data.upper()) #對收到的信息處理,返回到客戶端17 18 server.close() #關閉服務端socket_server
1 #客戶端2 import socket 34 address = ('localhost', 6666) #寫明要發送消息的服務端的地址和端口號5 client = socket.socket() 6 client.connect(address) #連接服務端78 client.send(b"hell world") #發送信息,注意在python3中socket的發送只支持bytes類型9 data = client.recv(1024) #等待接收服務端返回的信息10 print("client recv:", data)11 12 client.close() #關閉客戶端socket_client

例二(對上面的代碼進行改進,可以掛起多個連接,使每個連接可以進行多次對話且上一個連接斷開後下一個連接馬上接入):

1 #服務端2 import socket 34 address = ("localhost", 6666) #寫明服務端要監聽的地址,和端口號5 server = socket.socket() #生成一個socket對象6 server.bind(address) #用socket對象綁定要監聽的地址和端口7 server.listen(5) #開始監聽89 while True:10 #一條連接關閉後,接入下一條連接11 conn,addr = server.accept() #等帶新連接接入服務端,返回一個新的socket對象和地址,地址格式同前面格式12 '''13 Wait for an incoming connection. Return a new socket14 representing the connection, and the address of the client.15 '''16 while True:17 #使其可以接收多次消息18 data = conn.recv(1024) #接收信息,寫明要接收信息的最大容量,單位為字節19 # 沒收到消息,斷開本次連接20 if not data:21 break22 print("server recv:", data)23 conn.send(data.upper()) #對收到的信息處理,返回到客戶端24 25 server.close() #關閉服務端socket_server2
1 #客戶端2 import socket 34 address = ('localhost', 6666) #寫明要發送消息的服務端的地址和端口號5 client = socket.socket() 6 client.connect(address) #連接服務端78 while True: 9 #使其可以向服務端多次發送消息10 msg = input(">>>:").strip()11 #如果發送的消息為空,則不再發送12 if len(msg) == 0:13 break14 msg = msg.encode('utf-8') #將要發送的消息轉為bytes類型15 client.send(msg) #發送信息,注意在python3中socket的發送只支持bytes類型16 data = client.recv(1024) #等待接收服務端返回的信息17 print("client recv:", data.decode())18 19 client.close() #關閉客戶端socket_client2

例三(對例二稍加改造,就可實現一個簡單的ssh的服務端和客戶端):

1 #服務端2 import socket 3 import os 45 address = ("localhost", 8888) #寫明服務端要監聽的地址,和端口號6 server = socket.socket() #生成一個socket對象7 server.bind(address) #用socket對象綁定要監聽的地址和端口8 server.listen() #開始監聽9 10 while True:11 #一條連接關閉後,接入下一條連接12 conn,addr = server.accept() #等帶新連接接入服務端,返回一個新的socket對象和地址,地址格式同前面格式13 '''14 Wait for an incoming connection. Return a new socket15 representing the connection, and the address of the client.16 '''17 while True:18 data = conn.recv(1024) #接收信息,寫明要接收信息的最大容量,單位為字節19 # 沒收到消息,斷開本次連接20 if not data:21 break22 cmd_result = os.popen(data.decode(), 'r').read() #執行命令,將命令執行結果保存到cmd_result23 if len(cmd_result) == 0:24 '''命令執行結果為空,認為接收到錯誤命令'''25 cmd_result = "It's a wrong command..."26 27 while True:28 conn.send(str(len(cmd_result)).encode('utf-8')) #發送命令執行結果的長度29 confirm = conn.recv(1024).decode()30 '''客戶端確認收到數據長度,發送數據,否則重傳;且解決粘包問題'''31 if confirm == "OK":32 conn.send(cmd_result.encode('utf-8')) #對收到的信息處理,返回到客戶端33 break34 else :35 continue36 37 38 server.close() #關閉服務端ssh_socket_server
1 import socket 23 address = ("localhost", 8888) 4 client = socket.socket() 5 client.connect(address) 67 while True: 8 cmd = input("(command)>>>:").strip() 9 if len(cmd) == 0:10 '''發送空命令時,結束本次循環'''11 continue12 if cmd == "#exit":13 '''當檢測到#exit,客戶端與服務端斷開連接'''14 break15 16 client.send(cmd.encode()) #向服務端發送命令17 18 19 cmd_result = '' #目前已接收的數據20 size_data = 0 #目前已接收數據的長度21 size_cmd_result = int(client.recv(1024).decode()) #接收命令執行結果的長度22 client.send("OK".encode("utf-8")) #向服務端確認收到數據長度23 while size_data < size_cmd_result:24 '''命令的執行結果可能大於設置的接收buffersize,多次接收'''25 data = client.recv(1024).decode() #每次接收的數據26 size_data += len(data)27 cmd_result += data28 29 print(cmd_result)30 31 client.close()ssh_socket_client

注:提供另一種接收思路,服務端可以在每次返送完命令執行結果後,再發送一個結束標誌,當客戶端檢測到結束標誌時停止循環接收。

例四(改造例三,就可以實現一個簡單的ftp的服務端和客戶端)

1 #/usr/bin/python32 #服務端3 import socket 4 import os 5 import hashlib 67 address = ("0.0.0.0", 8888) #寫明服務端要監聽的地址,和端口號8 server = socket.socket() #生成一個socket對象9 server.bind(address) #用socket對象綁定要監聽的地址和端口10 server.listen() #開始監聽11 12 while True:13 #一條連接關閉後,接入下一條連接14 conn,addr = server.accept() #等帶新連接接入服務端,返回一個新的socket對象和地址,地址格式同前面格式15 '''16 Wait for an incoming connection. Return a new socket17 representing the connection, and the address of the client.18 '''19 while True:20 content = os.popen('ls', 'r').read()21 conn.send(content.encode('utf-8')) #與客戶端建立連接後,將服務端有哪些文件發給客戶端,供客戶端選擇22 filename = conn.recv(1024).decode() #接收客戶端發來的文件名23 24 if os.path.isfile(filename):25 '''文件存在,開始發送文件'''26 file_md5 = hashlib.md5() #初始化MD5對象,用於傳輸完成後的校驗27 file_size = os.stat(filename)[6] #讀取文件大小28 conn.send(str(file_size).encode('utf-8')) #將文件size發給客戶端29 confirm = conn.recv(1024).decode() #等待客戶端確認接收30 if confirm == "OK":31 '''發送文件數據'''32 with open(filename, 'rb') as fp:33 for line in fp:34 file_md5.update(line)35 conn.send(line)36 37 client_md5 = conn.recv(1024).decode() #傳輸完成後接收客戶端發來的MD538 if file_md5.hexdigest() == client_md5:39 '''確認文件傳輸未出錯'''40 conn.send("Success...".encode('utf-8'))41 else :42 '''文件傳輸出錯,提示客戶端刪除重傳'''43 conn.send("This file is changed, please delete it and try again...".encode('utf-8'))44 45 #客戶端未確認接收,重試46 else :47 conn.send("Error, try again...".encode('utf-8'))48 continue49 50 else :51 '''文件不存在,讓客戶端重新發送文件名'''52 conn.send("The file name is wrong and try again".encode('utf-8'))53 54 server.close() #關閉服務端ftp_socket_server
1 #/usr/bin/python32 import socket 3 import hashlib 45 address = ("192.168.56.50", 8888) 6 client = socket.socket() 7 client.connect(address) 89 while True:10 content = client.recv(4096) #接收並打印服務端有哪些文件11 print("Files List".center(75, '-'))12 print(content.decode())13 14 #向服務端發送想要接收的文件名15 filename = input("(You want to get)>>>:").strip()16 if filename == '#exit':17 break18 client.send(filename.encode('utf-8'))19 20 file_size = client.recv(1024).decode()21 if file_size.isdigit():22 '''文件大小是不小於0的數字,則文件存在,準備接收'''23 file_size = int(file_size)24 if file_size >= 0:25 data_size = 026 data_md5 = hashlib.md5() #初始化MD5對象,用以向服務端校驗27 client.send("OK".encode('utf-8')) #向服務端確認接收數據28 with open(filename, 'wb') as fp:29 while data_size < file_size:30 data = client.recv(1024)31 data_md5.update(data)32 data_size += len(data)33 fp.write(data)34 client.send(data_md5.hexdigest().encode('utf-8')) #發送服務端發送數據的MD5碼35 message = client.recv(1024).decode() #接收並打印服務端的校驗信息36 print(message)37 print('\n\n\n')38 else :39 '''文件大小不是數字,則出錯,打印服務端的提示信息'''40 print(file_size)41 continue42 43 client.close()ftp_socket_client

注意:如果代碼中有兩個(或兩個以上)socket.send()連在一起(中間無阻塞(比如time.slee(), socket.recv()等)),有粘包風險。

通過上面的代碼編寫,可以發現儘管socket已經簡化了網絡編程的過程,但還是給人一種面向過程的感覺。記下來的socketserver便解決了網絡服務端編程過於繁瑣的問題。

socketserver:

網絡編程Socket,神級程序員說通過這一篇文章讓你基本掌握!

網絡編程Socket,神級程序員說通過這一篇文章讓你基本掌握!

例五(我們使用socketserver實現例二):

網絡編程Socket,神級程序員說通過這一篇文章讓你基本掌握!

注:服務器類具有相同的外部方法和屬性,無論它們使用什麼網絡協議。

網絡編程Socket,神級程序員說通過這一篇文章讓你基本掌握!

注:其他協議的多線程實現同上。

謝謝閱讀,本文轉載文,原文

網絡編程Socket,神級程序員說通過這一篇文章讓你基本掌握!

如有侵權請聯繫小編刪除!

相關推薦

推薦中...