網路程式設計 socket 開發練習題
阿新 • • 發佈:2018-12-01
1 什麼是C/S架構
c指的是client(客戶端軟體),S指的是Server(服務端軟體),C/S架構的軟體,實現服務端軟體與客戶端軟體基於網路通訊
2 網際網路協議是什麼?分別介紹五層協議中每一層的功能
網際網路協議就是計算機界的通訊標準
物理層功能:主要是基於電器特性發送高低電壓(電訊號),高電壓對應數字1,低電壓對應數字0
資料鏈路層的功能:定義了電訊號的分組方式
網路層功能:引入一套新的地址用來區分不同的廣播域/子網,這套地址即網路地址
傳輸層功能:建立埠到埠的通訊 補充:埠範圍0-65535,0-1023為系統佔用埠
應用層功能:將應用程式的資料打包傳給傳輸層
3 基於tcp協議通訊,為何建立連結需要三次握手,而斷開連結卻需要四次揮手
三次握手:client傳送請求建立通道;server收到請求並同意,同時也傳送請求建通道;client收到請求並同意,建立完成
四次揮手:client傳送請求斷開通道;server收到請求並同意,但是這時sever可能還在發資料,並不關閉介面,所有回覆同意和傳送sever斷開請求不是一同傳送的;等到資料傳送完畢server也傳送請求斷開通道;client受到訊息結束
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 sev = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sev.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sev.bind(('127.0.0.1', 9999)) sev.listen(5) print('starting...') while True: conn, client_addr = sev.accept() print(conn) print(client_addr) while True: try: data = conn.recv(1024) print(data.decode()) inp = input('-->').strip() conn.send(inp.encode()) except ConnectionResetError: break conn.close() sev.close()
import socket cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM) cli.connect(("127.0.0.1", 9999)) while True: inp = input('---->').strip() if not inp: continue cli.send(inp.encode()) data = cli.recv(1024) print(data.decode()) cli.close()
9 基於tcp socket,開發簡單的遠端命令執行程式,允許使用者執行命令,並返回結果
import socket import subprocess import json import struct sev = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sev.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sev.bind(('127.0.0.1', 5555)) sev.listen(5) print('start'.center(50, '-')) while True: conn, addr = sev.accept() while True: try: cmd = conn.recv(1024) obj = subprocess.Popen(cmd.decode(), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = obj.stdout.read() stderr = obj.stderr.read() total_size = len(stdout)+len(stderr) dict_msg = {'file_name': 'a.txt', 'md5': 12431564, 'total_size': total_size} dict_bytes = json.dumps(dict_msg).encode() header = struct.pack('i', len(dict_bytes))[0] conn.send(header) conn.send(dict_bytes) conn.send(stdout) conn.send(stderr) except ConnectionResetError: break conn.close() sev.close()
import socket import struct import json cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM) cli.connect(('127.0.0.1', 5555)) while True: cmd = input('-->') if not cmd: continue cli.send(cmd.encode()) obj = cli.recv(4) header_len = struct.unpack('i', obj)[0] header = cli.recv(header_len) dict_msg = json.loads(header.decode()) total_size = dict_msg['total_size'] recv_size = 0 recv_data = b'' while recv_size < total_size: data = cli.recv(1024) recv_size += len(data) recv_data += data print(recv_data.decode('gbk')) cli.close()
10 基於tcp協議編寫簡單FTP程式,實現上傳、下載檔案功能,並解決粘包問題
import json import socket import os import struct BASE_DIR = os.path.dirname(os.path.abspath(__name__)) SHARE_PATH = os.path.join(BASE_DIR, 'share') print(SHARE_PATH) class Sever(): def __init__(self): print('start....') self.ser = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.ser.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.ser.bind(('127.0.0.1', 9999)) self.ser.listen(5) self.run() def run(self): while True: self.conn, self.client_addr = self.ser.accept() while True: try: cmd_b = self.conn.recv(1024) cmd, file_name = cmd_b.decode().split() if hasattr(self, cmd): func = getattr(self, cmd) func(file_name) else: print('none...') except ConnectionResetError: break def get(self, file_name): '''客戶端下載''' if os.path.exists('%s\%s' % (SHARE_PATH, file_name)): file_size = os.path.getsize('%s\%s' % (SHARE_PATH, file_name)) dict_msg = {'file_name': file_name, 'md5': 124521, 'file_size': file_size, 'file': True} header = json.dumps(dict_msg).encode() header_size = len(header) self.conn.send(struct.pack('i', header_size)) self.conn.send(header) with open('%s\%s' % (SHARE_PATH, file_name), 'rb') as f: for line in f: self.conn.send(line) else: print('send has done...') else: dict_msg = {'file_name': file_name, 'md5': 124521, 'file_size': None, 'file': False} header = json.dumps(dict_msg).encode() header_size = len(header) self.conn.send(struct.pack('i', header_size)) self.conn.send(header) print('file not exist') def put(self, file_name): '''客戶端上傳''' obj = self.conn.recv(4) header_len = struct.unpack('i', obj)[0] header = self.conn.recv(header_len) dict_msg = json.loads(header.decode()) file_size = dict_msg['file_size'] with open('%s\%s' % (SHARE_PATH, file_name), 'wb')as f: recv_size = 0 while recv_size < file_size: data = self.conn.recv(1024) f.write(data) recv_size += len(data) print("%s 接受完成" % file_name) sever = Sever()
import socket import json import struct import os BASE_DIR = os.path.dirname(os.path.abspath(__name__)) DOWMLOAD_PATH = os.path.join(BASE_DIR, 'download') class Client(): def __init__(self): self.cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.cli.connect(("127.0.0.1", 9999)) print('go....') while True: inp = input('-->').strip() if not inp: continue try: cmd, file_name = inp.split() except ValueError: print('輸入不合法') continue self.cli.send(inp.encode()) if hasattr(self, cmd): func = getattr(self, cmd) func(file_name) def get(self,file_name): obj = self.cli.recv(4) header_size = struct.unpack('i', obj)[0] header = self.cli.recv(header_size) dict_msg = json.loads(header.decode()) if dict_msg['file']: file_size = dict_msg['file_size'] recv_size = 0 with open("%s\%s" % (DOWMLOAD_PATH, file_name), 'wb')as f: while recv_size < file_size: data = self.cli.recv(1024) f.write(data) recv_size += len(data) print('%s 下載完成 ' % file_name) else: print('%s 不存在 ' % file_name) def put(self,file_name): if os.path.exists('%s\%s' % (DOWMLOAD_PATH, file_name)): file_size = os.path.getsize('%s\%s' % (DOWMLOAD_PATH, file_name)) dict_msg = {'file_name': file_name, 'md5': 124521, 'file_size': file_size, 'file': True} header = json.dumps(dict_msg).encode() header_size = len(header) self.cli.send(struct.pack('i', header_size)) self.cli.send(header) with open('%s\%s' % (DOWMLOAD_PATH, file_name), 'rb') as f: for line in f: self.cli.send(line) else: print('send has done...') else: print('file not exist')
11 基於udp協議編寫程式,實現功能
import socket sev = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sev.bind(('127.0.0.1', 9999)) print('start...') while True: msg, client_addr = sev.recvfrom(1024) print(msg.decode()) inp = input('-->').strip().encode() sev.sendto(inp, client_addr)
import socket cli = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) while True: inp = input('-->').strip() cli.sendto(inp.encode(), ('127.0.0.1', 9999)) msg, sever_addr =cli.recvfrom(1024) print(msg.decode())