异常处理:
try:
把有可能抛出异常的代码块缩进
except 异常类型1 as x: 去捕捉异常
对异常处理的代码
except (异常类型,异常类型3) as x:
对异常处理的代码
except Exception: 万能异常
pass
else:
没有异常发出执行的代码
finally:
不处理异常,无论是否发生异常都会执行finally的子代码
finally可以单独与try配送使用 可以和except一起使用 except捕捉异常
finally: 应该把被检测代码中回收系统资源的代码放到这里
不处理异常,无论是否发生异常都会执行finally的子代码
cs架构与bs架构
Client<==========>Server
c是指软件架构的一种方式,s是服务端 客户端软件 标准自己定
客户端软件 类似于send 服务端软件recv
操作系统 操作系统
计算机硬件 <=====互联网 物理链接物质=======> 计算机硬件
bs架构 一种特殊的cs架构
Browser浏览器(不用写)<==================>Server
标准根据浏览器来定
网络存在的意义:就是跨地域数据传输 称之为通信
网络=物理链接介质+互联网通信协议
五层协议:
应用层(应用层、表示层、会话层)
传输 层 段 就端口 TCP、udp
网络层 包 ip地址 要达到的目的:划分广播域
每一个广播域但凡要接通外部,一定要有一个网关帮内部的计算机转发包到公网
数据链路层 ethernet以太网协议,帧 管的是Mac地址
规定1:一组数据称之为一个数据帧 规定2:数据帧分为两部分=>头+数据
物理层 一组物理层称之为:位 负责发送电信号,
单纯的电信号无意义,必须对其进行分组
协议:规定数据的组织格式
格式:头部+数据部分
封包裹的过程:数据外加头
拆包裹的过程:拆掉头获取数据
ip+mac可以标识全世界范围内独一无二的一台计算机
arp协议可以自动将 ip地址自动解析成Mac地址
网关和网关之间用的是互联网协议
端口port:
ip+mac+port=>可以标识全世界范围内独一无二的一个基于网络通信的应用程序
应用层(应用层、表示层、会话层)
传输 层 段 就端口 TCP、udp都是基于端口的
网络层 包 ip地址
数据链路层 Mac ethernet以太网 帧
物理层
客户端:socket 会把应用层以下的层级进行封装,服务端也一样进行解包
ethernet以太网头+ip头+TCP头+应用层的头+应用层书数据
一.传输层:TCP协议 可靠(好人协议)、udp 速度快,发数据不需要确认=》基于端口
TCP协议 是可靠传输的
发送数据必须等到对方确认后才算完成,才会将自己内存中的数据清除
ps:当服务端大量处于TIME_WAIT状态时意味着服务端正在经历高并发
TCP协议的半连接池:
backlog
[链接请求1,链接请求2,链接请求3,链接请求5]
端口范围0-65535,0-1023为系统占用端口
ip=port=》标识全世界范围内独一无二的一个基于网络通信的应用程序
基于TCP协议通信:必须建立一个双向通信的链接
c------------------------->s
c<------------------------s
三次握手建立链接,是为了传输数据做准备 syn =1跟他建链接 ack=1 确认建立链接的信息
四次挥手断开连接,由于链接内有数据传输 所以必须分4次断开
二、应用层
应用层:可以自定义协议==》头部+数据部分
http\https\ftp
自定义协议需要注意的问题:
两大组成部分=头部+数据部分
1.头部:发给对数据 描述信息 比如想要发给谁,数据的类型、长度
数据部分:想要发的数据
2.头部的长度必须固定
因为接受端要通过头部获取所接接受数据的详细信息
文件名不能起socket 127.0.0.1 局域网也访问不到 只有自己这台能访问 一半在测试的时候用
一:服务端
import socket #先导入通信模块
#1.买手机
phone=socket.socket(AF_INET ,socket.SOCK_STREAM)
socket模块在有一个接口叫:socket(是一个类)
加括号传参数参数是 socket.AF_INET (地址家族 是基于网络通信的)
后面写套接字是基于什么协议通信,STREAM 流式协议(没有开头没有结尾)指的是==》TCP协议(如果要用udb协议的话是:socket.SOCK_DGRAM 数据报协议)
2.绑定手机卡(标识全世界范围内独一无二的一个基于网络通信的应用程序ip+port)
phone.bind(('127.0.0.1',8080))
#127.0.0.1 局域网也访问不到 只有自己这台能访问 一半在测试的时候用 端口范围0- 65535,0-1023为系统占用端口
3.开机 一但开机就属于听状态
phone.listen(5) #backlog=5指的是半连接池的大小 可以只写5 开机和绑定手机应该写到服务端的配置文件里面去
4.等待电话连接请求:拿到电话连接coon
#加上链接循环 才能使得服务端一直工作
while True:
conn,client_addr=phone.accept() # accept没有参数 如果listen监听到半连接池里面有信息过来 accept就拿走 返回值是一个元组形式,三次握手的双向通路就是conn
#client_addr是客户端的ip和端口
print(conn)
print(''客户端ip和端口'':client_addr)
5.通信 收\发消息
while True:
try:
data=coon.recv(1024) #最大接受的数据量为1024Bytes,收到的是Bytes类型等同于二进制 ===》收消息
if len(data)==0:#在unix系统,一旦data收到的是空
意味着是一种异常的行为:客户违法断开了连接
break
print("客户端发来消息:",date.decode('utf=8')) #解码
coon.send(date.upper()) #====>发消息 例如回一个全大写过去
except Exception: #针对Windows系统
break
6.关闭电话连接coon(必选的回收资源操作)
conn.close() #挂断电话 接通下一个电话
7.关机(可选择操作)
phone.close()
二.客户端 客户端无需固定绑定 只有服务才需要绑定不变
1.买手机
phone=socket.socket(AF_INET ,socket.SOCK_STREAM)
socket模块在有一个接口叫:socket(是一个类)
加括号传参数参数是 socket.AF_INET (地址家族 是基于网络通信的)
后面写套接字是基于什么协议通信,STREAM 流式协议(没有开头没有结尾)指的是==》TCP协议(如果要用udb协议的话是:socket.SOCK_DGRAM 数据报协议)
2.拨通服务端电话
phone.connect(('127.0.0.1',8080))
3.通信
while True:
msg=input('请输入要发送的内容:').strip()
phone.send(msg.encode('utf-8')) #转为Bytes类型 类似于二进制 发消息 编码
date=phone.recv(1024)
print(date.decode('utf-8'))
4.关闭链接(必选的回收资源操作)
phone.close()
解决沾包和并发后:
客户端:
from socket import * #导入所有的socket里的 后面就不用使用时.socket了
client=socket(AF_INET,SOCK,SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
msg=input('请输入命令:').strip()
if len(msg)==0:continue
client.send(msg.encode('utf-8'))
cmd_res=client.recv(1024) #本次接受最大1024Bytes
print(cmd_res)
服务端:
服务端应该满足的两个特点:
1.一直对外提供服务
2.并发的服务多个客户端
import subprocess
import struct
import ison
from socket import *
server=socket(AF_INET,SOCK_STREAM)
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它 再bind前加
server.bind(('127.0.0.1',8080))
server.listen(5)
服务端应该做两件事:
第一件事:循环地从连接池中取出链接请求与其建立双向链接,拿到链接对象
while True:
conn,client_addr=server.accept()
第二件事:拿到链接对象,与其进行通信循环
stdout_res=obj.stdout.read()
stderr_res=obj.stderr.read()
total_size=len(stdout_res)+len(stderr_res)
1.先发头信息(固定长度的bytes):对数据的描述信息
int--》固定长度的bytes
header=struct.pack('i',total_size)
conn.send(header)
发头消息
json_str=json.dumps(header_dic)
2.再发真实的数据
conn.send(stdout_res)
conn.send(stderr_res)
except Exception:
break
conn.close()
长度固定:
将整形int转换为Bytes类型 用模块:struct .pack('i',xx) i对应的是字节 4个
解包操作:struck.unpack('i',x) 解包出来的是一个小元组 第一个值是最开始我们打包进去的
loads
将字典转为bytes:用pack(同平台python之间使用)或者json(不同平台之间使用)
import socketserver 支持并发的模块
class MyRequestHandle(socketserver.BaseRequestHandler) : #先建一个类起一个类名字
def handle(self):必须写一个方法handle
print(self,request) #如果是TCP协议,self.request就是我们之前拿到的sonn对象链接对象
print(self.client_address) 就是客户端的ip地址
socketserver.ThredingTCPServer(('127.0.0.1',8888),MyRequestHandle)
#这是Windows底下的调用线程 Threding的意思是线程
s.serve_forever() 就会把底层封装好
import socketserver #一定要捕捉异常和关闭
class MyRequestHandle(socketserver.BaseRequestHandler) : #先建一个类起一个类名字
def handle(self):必须写一个方法handle
#print(self,request) #如果是TCP协议,self.request就是我们之前拿到的sonn对象链接对象
print(self.client_address)
while True:
try:
msg=self.request.recv(1024)
if len(msg)==0:break
self.request.sen(msg.upper())
except Exception:
break
self.request.close()
标签:协议,socket,ip,self,并发,异常,链接,服务端 From: https://www.cnblogs.com/97zs/p/17693397.html