python網絡編程課後練習
1、什麽是C/S架構?
客戶端/服務器架構。實現服務端軟件與客戶端軟件基於網絡的通信。
2、互聯網協議是什麽?分別介紹五層協議中每一層的功能?
互聯網協議是指用於互聯網通信的規範。分為:osi七層、tcp/ip五層、tcp/ip四層
物理層:基於電氣特性發送高低電壓,高電壓用1,低電壓用0
數據鏈路層:通過Ethernet協議標準將電信號進行分組
網絡層:引入一套新的地址用來區分不同的廣播域/子網,這套地址即網絡地址
傳輸層:建立端口到端口的通信,使用TCP/UDP協議
應用層:發起請求,使用http/ftp/自定義協議
3、基於tcp協議通信,為何建立鏈接需要三次握手,而斷開鏈接卻需要四次揮手
三次握手:首先客戶端給服務端發送一個syn包請求連接;服務端收到之後會對客戶端的請求作出回應,發送一個ack包給客戶端,並且同時將一個syn包發送給客戶端請求連接,即發送syn包+ack包;客戶端收到syn包+ack包之後,對服務端的請求作出確認,發送一個ack包給服務端,此時,完成三次握手,客戶端和服務端開始收發數據。
斷開連接的時候,TCP也需要互相確認才可以斷開連接,采用四次揮手斷開一個連接,客戶端如果發送完數據,就給服務端發送一個斷開連接的請求,服務端收到請求後,給客戶端發送一個確認信息,服務端接收完數據之後給客戶端發送斷開連接的請求,客戶端收到消息後給服務端發送一個確認消息,至此,連接斷開。
這樣做的原因是,兩端數據的接收並不是同時進行的,數據大小也不一樣,如果三次揮手有可能導致一端的數據接收不完整。
4、為何基於tcp協議的通信比基於udp協議的通信更可靠?
tcp協議是面向鏈接的協議,在通信過程中,雙方通過三次握手建立連接、四次揮手斷開連接,發送方給接收方發送數據,如果沒有得到接收方的回應,就會繼續給它發消息,直到接收方回應。
udp是面向數據報的協議,不需要三次握手建立連接,它不會管接收方有沒有收到數據。
5、流式協議指的是什麽協議,數據報協議指的是什麽協議?
流式協議指TCP協議,是通過三次握手建立連接再發送數據的,會存在粘包現象,當發送空消息時,對方並不會收到,不一定是一個send就要對應一個recv,傳輸效率低,網絡開銷大,可靠性高。
數據報協議是指UDP協議,是以消息為單位發送的數據的,一個sendto就對應一個recvfrom,不會存在粘包現象,即使發送空消息也能收到,傳輸效率高,網絡開銷小,可靠性低。
6、什麽是socket?簡述基於tcp協議的套接字通信流程
socket是介於應用層和傳輸層之間的一組接口。將復雜的TCP/IP協議封裝到接口裏面,使用者只需要知道怎麽用即可,不需要關心底層的實現。
基於TCP的套接字通信流程:
1)服務端:創建一個套接字對象;綁定本機地址信息;開始時監聽;接收連接;
2)客戶端:創建套接字對象;主動連接客戶端;等待對方接收
通過三次握手後建立連接,開始收發消息。
收發消息完了之後,通過四次揮手斷開連接。
7、什麽是粘包? socket 中造成粘包的原因是什麽? 哪些情況會發生粘包現象?
粘包是指兩次命令執行的結果黏在一起。粘包發生在TCP協議中。
造成粘包的原因:接收方不知道所要接收消息的大小和界限。
發生粘包的情況:1、socket緩沖區導致,socket為了提高傳輸效率,往往會將較短時間間隔內較小的數據包合並發送,這樣接收方就會收到一個粘包數據;
2、接收方不知道該接收多大數據量,當接收方的最大接收量小於消息大小時,會發生粘包。
8、基於socket開發一個聊天程序,實現兩端互相發送和接收消息
# 服務端 import socket server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1) server.bind(("127.0.0.1", 8080)) server.listen(5) print("starting.....") while True: conn, client_addr = server.accept() if not conn: break while True: msg = conn.recv(1024) print("from aa:", msg.decode()) if msg.decode() == "bye": break inp = input("me:").strip() conn.send(inp.encode()) conn.close() server.close() # 客戶端 import socket client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) client.connect(("127.0.0.1", 8080)) while True: msg = input("me:").strip() client.send(msg.encode()) if msg == "bye": break msg1 = client.recv(1024) print("from xx:", msg1.decode()) client.close()View Code
9、基於tcp socket,開發簡單的遠程命令執行程序,允許用戶執行命令,並返回結果
# 服務端 import socket import subprocess import struct s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(("127.0.0.1", 8080)) s.listen(3) while True: print("starting....") conn,addr = s.accept() if not conn: break while True: cmd = conn.recv(1024).decode() if not cmd: break res = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) stdout = res.stdout.read() stderr = res.stderr.read() res_len = len(stdout)+len(stderr) len_struct = struct.pack("i", res_len) conn.send(len_struct) conn.send(stdout) conn.send(stderr) conn.close() s.close() # 客戶端 import socket import struct c = socket.socket(socket.AF_INET, socket.SOCK_STREAM) c.connect(("127.0.0.1", 8080)) while True: cmd = input("input command:").strip() c.send(cmd.encode()) if not cmd: break header = c.recv(4) header_len = struct.unpack("i", header)[0] res = c.recv(header_len) print("command results:", res.decode("gbk")) c.close()View Code
10、基於tcp協議編寫簡單FTP程序,實現上傳、下載文件功能,並解決粘包問題
# 服務端 import socket import os import json import struct class Server: host = "127.0.0.1" port = 8080 max_recv = 512 serverfile = r"D:\code2\ex\刪除\文件傳輸\server\serverfile" def __init__(self): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.bind((self.host, self.port)) self.sock.listen(2) def get(self, filename): """下載文件 制作報頭,json,拿到報頭大小,壓縮報頭長度為4,發送報頭長度,發送報頭,發送文件""" header_dic = {"filename": filename, "md5": "xxx", "file_size": os.path.getsize(os.path.join(self.serverfile, filename))} header_bytes = json.dumps(header_dic).encode() header_len = len(header_bytes) header_struct = struct.pack("i", header_len) self.conn.send(header_struct) self.conn.send(header_bytes) with open(os.path.join(self.serverfile, filename), "rb") as f: for line in f: self.conn.send(line) def put(self, filename): """上傳文件 拿到報頭長度,解壓報頭長度,接收報頭,json,拿到文件大小,接收文件""" header_struct = self.conn.recv(4) header_len = struct.unpack("i", header_struct)[0] header_bytes = self.conn.recv(header_len) header_dic = json.loads(header_bytes.decode()) file_size = header_dic["file_size"] recv_size = 0 with open(os.path.join(self.serverfile, filename), "wb") as f: while recv_size < file_size: content = self.conn.recv(self.max_recv) f.write(content) recv_size += len(content) def run(self): while True: print("starting....") self.conn,self.addr = self.sock.accept() if not self.conn: break while True: cmd = self.conn.recv(self.max_recv).decode() if not cmd: break cmds = cmd.strip().split() if hasattr(self, cmds[0]): func = getattr(self, cmds[0]) func(cmds[1]) self.conn.close() self.sock.close() server = Server() if __name__ == "__main__": server.run() # 客戶端 import socket import os import json import struct class Client: host = "127.0.0.1" port = 8080 max_recv = 512 localfile = r"D:\code2\ex\刪除\文件傳輸\client\localfile" def __init__(self): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect((self.host, self.port)) def get(self, filename): """下載文件 接收報頭大小,解壓報頭大小,接收報頭,json, 拿到文件大小,接收文件,存儲文件 """ header_struct = self.sock.recv(4) header_len = struct.unpack("i", header_struct)[0] header_bytes = self.sock.recv(header_len) header_dic = json.loads(header_bytes.decode()) file_size = header_dic["file_size"] recv_size = 0 with open(os.path.join(self.localfile, filename), "wb") as f: while recv_size < file_size: content = self.sock.recv(self.max_recv) f.write(content) recv_size += len(content) print("下載成功!") def put(self, filename): """上傳文件 制作報頭,json,壓縮報頭長度,發送報頭長度,發送報頭,發送文件""" header_dic = {"filename": filename, "md5":"xxxx", "file_size":os.path.getsize(os.path.join(self.localfile, filename))} header_bytes = json.dumps(header_dic).encode() header_len = len(header_bytes) header_struct = struct.pack("i", header_len) self.sock.send(header_struct) self.sock.send(header_bytes) with open(os.path.join(self.localfile, filename), "rb") as f: for line in f: self.sock.send(line) print("上傳成功!") def run(self): while True: cmd = input("input command:").strip() if not cmd: break cmds = cmd.split() if len(cmds) == 2 and hasattr(self, cmds[0]): self.sock.send(cmd.encode()) func = getattr(self, cmds[0]) func(cmds[1]) self.sock.close() client = Client() if __name__ == "__main__": client.run()View Code
11、基於udp協議編寫程序,實現功能
1)執行指定的命令,讓客戶端可以查看服務端的時間
2)執行指定的命令,讓客戶端可以與服務的的時間同步
# 服務端 import socket import time import subprocess server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) server.bind(("127.0.0.1", 8080)) # 綁定IP、端口 while True: cmd,addr = server.recvfrom(1024) if not addr: break print(cmd.decode(), addr) if cmd.decode() == "time": # 返回服務端時間 time_now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) # 當前日期時間 server.sendto(time_now.encode("gbk"), addr) # 發送 else: # 解析命令 obj = subprocess.Popen(cmd.decode(), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = obj.stdout.read() stderr = obj.stderr.read() server.sendto(stdout+stderr, addr) server.close() # 客戶端 import socket client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) addr = ("127.0.0.1", 8080) while True: cmd = input(">>>").strip() if not cmd: break client.sendto(cmd.encode(), addr) # 發送命令 msg, addr_server = client.recvfrom(1024) # 接收消息 print(msg.decode("gbk")) client.close()View Code
python網絡編程課後練習