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())