网络编程小结
程序员文章站
2022-05-05 07:51:54
[TOC] 软件开发架构 C/S架构 client:客户端 server:服务端 优点:软件的使用稳定,网络资源占用少 缺点: 若需要使用多个软件,需要下载多个客户端 服务端更新后,用户也需要跟着下载更新 B/S架构 browser:浏览器 server:服务端 优点:以浏览器充当客户端,服务端更新 ......
软件开发架构
c/s架构
client:客户端
server:服务端
优点:软件的使用稳定,网络资源占用少
缺点:
- 若需要使用多个软件,需要下载多个客户端
- 服务端更新后,用户也需要跟着下载更新
b/s架构
browser:浏览器
server:服务端
优点:以浏览器充当客户端,服务端更新不需要用户更新下载
缺点: 占用网络资源大,网络不好时,体验差
互联网osi七层协议
从下往上分为:
物理层--> 数据链路层--> 网络层--> 传输层--> 会话层--> 表示层--> 应用层
物理层
传输电信号 0100011
数据链路层
规定好电信号的分组方式
必须要由一块网卡
-
mac地址:12位唯一的16进制数
前6位是厂商号
后6位是流水号
-
以太网协议:
- 在同一个局域网内通信
- 单播 1对1吼
- 广播 多对多吼
- 会有广播风暴, 不能对局域网通信
- 在同一个局域网内通信
网络层
ip:定位局域网位置
port: 端口,唯一标识一台计算机上的一个程序
arp协议:将mac地址获取,并解析成ipi地址
传输层
tcp协议
tcp协议称之为流式协议
若想要通信,必须建立连接,并建立双向通道
三次握手,四次挥手:
- 三次握手建立连接
- 客户端往服务端发送建立通道
- 服务端要确认客户端的请求,并往客户端也发送请求建立通道
- 客户端接收到服务端建立连接的请求,并返回确认
- 建立双向通道
- 双向通道
- 反馈机制
- 客户端往服务端发送请求获取数据,服务端务必返回数据,客户端确认收到,否则会反复发送,一直到某个时间段内,会停止发送
- 四次挥手断连接
- 客户端往服务端发送断开连接请求,服务端返回确认收到
- 服务端需要再次发送断开连接请求
- 客户端返回确认收到
- 最终确认断开来连接
udp协议
- 数据不安全
- 不需要建立双向通道
- 传输速度快
- 不会由粘包问题
- 客户端发送数据,不需要服务端确认收到
应用层
ftp、http
socket套接字
socket用来写套接字客户端与服务端的模块,内部帮我们封装好了7层协议需要做的事情.
socket套接字模板
# 服务端 import socket server = socket.socket() server.bind( ('127.0.0.1', 9527) ) server.listen(5) while true: conn, addr = server.accept() print(addr) while true: try: data = conn.recv(1024) if len(data) == 0: continue print(data.decode('utf-8')) conn.send(data) except exception as e: print(e) break conn.close() # 客户端 import socket client = socket.socket() client.connect( ('127.0.0.1', 9527) ) while true: send_msg = input('客户端:') client.send(send_msg.encode('utf-8')) data = client.recv(1024) print(data.decode('utf-8'))
subprocess
用来通过代码往cmd创建一个管道,并且发送命令和接收cmd返回的结果
# 伪代码: import subprocess obj = subprocess.popen( '命令', shell=true, stdout=subprocess.pipe, stderr=subprocess.pipe ) msg = obj.stdout.read() + obj.stderr.read()
粘包问题
- 不能确定对方发送数据的大小
- 在短时间内,间隔时间短,并且数据量小的情况下,默认将这些数据打包成一个多次发送的数据,然后一次性发送
struct解决粘包问题
可以将一个数据的长度打包成一个固定长度的报头. struct.pack('模式i', '源数据长度') data = 'gagawagwaga' # 打包成报头 headers = struct.pack('i', len(data)) # 解包获取数据真实长度 data = struct.unpack('i', headers)[0]
# 服务端 import socket import subprocess import struct server = socket.socket() server.bind( ('127.0.0.1', 9527) ) server.listen(5) while true: conn, addr = server.accept() print(addr) while true: try: cmd = conn.recv(1024).decode('utf-8') if len(cmd) == 0: continue obj = subprocess.popen( cmd, shell=true, stdout=subprocess.pipe, stderr=subprocess.pipe ) res = obj.stdout.read() + obj.stderr.read() headers = struct.pack('i', len(res)) conn.send(headers) conn.send(res) except exception as e: print(e) break conn.close() # 客户端 import socket import struct client = socket.socket() client.connect( ('127.0.0.1', 9527) ) while true: cmd = input('客户端输入命令:') client.send(cmd.encode('utf-8')) headers = client.recv(4) data_len = struct.unpack('i', headers)[0] data= client.recv(data_len) print(data.decode('gbk'))
升级版: 先将数据存放到字典中,将字典打包发送过去
字典的好处:真实数据长度;文件的描述信息;发送的数据更小
socketserver
# 服务端 import socketserver class mytcpserver(socketserver.baserequesthandler): def handle(self): print(self.client_address) while true: try: data = self.request.recv(1024).decode('utf-8') send_msg = data.upper() self.request.send(send_msg.encode('utf-8')) except exception as e: print(e) break if __name__ == '__main__': server = socketserver.threadingtcpserver( ('127.0.0.1', 9527), mytcpserver ) server.serve_forever()