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