异常处理与网络基础 & 计算机组成原理
一.异常处理与网络基础
1.异常处理目的是防止程序的奔溃
异常处理的两种方式对比,if判断型和except..as...
1.1if类型
age = input(">>:") if age.isdigit(): int(age) elif age.isspace(): print("---->用户输入的空格") elif len(age) == 0: print("---->用户输入的为空") else: print("其他的非法输入")
1.2try,exception类型
try: age=input("1>>:") int(age) num2 = input("2>>:") int(num2) l=[] l[10000] dic = {} dic["name"] except Exception as e: print(e) print("1111111")
1.3自定义异常
class EgonException(BaseException): def __init__(self,msg): self.msg = msg print(EgonException("自己定制的异常"))
1.4try,except Exception,else 框架
try: xxxx xxxx except Exception as e: print("xxxx",e) else: xxxx
1.5try,except Exception as e,else,finally框架
try: age = input("1>>:") int(age) except ValueError as e: print(e) except Exception as e: print(e) else: print("其他的非法输入") finally: print("finally")
1.6assert raise框架
res1=1 assert res1 == 2 #如果res1 !=1,自动抛出AssertionError异常
1.7assert raise等于如下框架
if res1!=1:raise AssertionError
2.IOS七层协议:
第一层:物理层,负责物理设备的连接,实现两台机器间线与线的通信
第二层:数据链路层,是物理层和网络层的中间桥梁,为网络层传输数据做好准备,数据以一帧一帧的方式传送
第三层:网络层,这层是端对端的传输定义,包括定义IP地址,路由地址等
第四层:传输层,接受数据以差错恢复协议或无差错恢复协议,比如TCP或UDP形式
第五层:会话层是建立在传输层之上,利用传输层提供的服务,使应用建立和维持会话,并能使会话获得同步。会话层使用校验点可使通信会话在通信失效时从校验点继续恢复通信
第六层:这一层主要用于定义数据格式和加密
第七层:应用层,与其他计算机进行通讯的一个应用,是对应应用程序的通信服务的
网络IP,可以标识具体的房间名
IP和端口用于定位互联网中位移的程序
3.基于TCP协议的套接字编程:
3.1基于服务端和客户端的发送与接收
#服务端 import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #socket()买手机 phone.bind(("192.168.1.4",8000)) #bind()绑定手机卡 phone.listen(5) #listen()开机 conn,addr = phone.accept() #accept()等电话,拿到一个电话链接 msg = conn.recv(1024) print('客户端发来的消息是:',msg) conn.send(msg.upper()) #发消息 conn.close() phone.close() #关机 #客户端 import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #socket()买手机 phone.connect(("192.168.1.4",8000)) #connect() 建立连接 phone.send("hello".encode("utf-8")) #write() 发消息 data = phone.recv(1024) #read() 回收从服务端发来的数据 print("收到服务端发来的消息:",data)
4.TCP的三次握手与四次挥手
三次握手 three-way handshake,是指建立一个TCP连接时,需要客户端和服务端总共发送3个包确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发,整个流程如图1,
图1 服务端和客户端三次握手模型
第一次握手:Client将标志位SYN置1,随机产生seq=J,并将数据发送给Server,Server等待接受数据,Client进入SYN_SENT状态,等待Server确认。
第二次握手:Server收到数据包后由标志位SYN=1只Client请求建立连接,Server将标志位SYN和ACK都置1,ack=J+1,随机产生一个值seq=K,并将数据包发送给Client请求建立连接,此时Server进入SYN_RCVD状态。
第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client和Server可以开始传送数据。
SYN攻击:当Server上有大量半连接状态且源IP地址是随机的,则可以认为遭到SYN攻击,SYN攻击就是Client在短时间内伪造大量不存在的IP地址,将包发给Server,因此Server回复确认包,并等待Client确认,由于源地址不存在,因此,Server需要不断重发直至超时,导致正常的SYN请求由于伪造的SYN包占满为连接队列而被丢弃,导致网络堵塞瘫痪。如下命令可以用过滤出伪造SYN请求
#netstat - nap | grep SYN_RECV
四次挥手:four-way wavehand,是指终止TCP连接,指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这个过程由客户端或服务端任一方执行close来触发,流程如图2,TCP连接是全双工的,所以每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不再收到数据了,但是这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。
图2 四次挥手模型
第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接受,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
总结下就是,Client先向Server发送关闭传输数据的请求,等待确认。待Server确认后,关闭Client到Server的传输数据请求。接着Server发送关闭Server到Client的关闭传输数据请求。待Client确认后,关闭Server到Client的传输数据请求。
为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。
5.服务端和客户端循环收发消息
收发过程中先运行服务端程序,在运行客户端程序
back_log指出有多少个SYN请求可以被存于堆栈中
buffer_size指出索引缓存区的大小,决定索引处理的速度
服务端程序:
from socket import * ip_port = ("192.168.1.4",8000) back_log = 5 buffer_size = 1024 tcp_server = socket(AF_INET,SOCK_STREAM) #买手机 tcp_server.bind(ip_port) #绑定手机卡 tcp_server.listen(back_log) #开机 conn,addr = tcp_server.accept() #等待接听 #链接池,传送速率 print("双向链接是",conn) print('客户端地址:',addr) while True: data = conn.recv(buffer_size) #接听成功 print("客户端发来的消息",data.decode("utf-8")) conn.send(data.upper()) #发送消息 conn.close() #通话完成 tcp_server.close() #关机
客户端程序:
from socket import * ip_port = ("192.168.1.4",8000) back_log = 5 #指出有多少个SYN请求可以被存于堆栈中 buffer_size = 1024 #指定索引缓存区大小,决定索引处理的速度 tcp_client = socket(AF_INET,SOCK_STREAM) #开机 tcp_client.connect(ip_port) #连接 while True: msg = input(">>>") tcp_client.send(msg.encode("utf-8")) #发送数据到服务端 data = tcp_client.recv(buffer_size) #接受服务端数据 print("data from server are ...",data.decode("utf-8")) tcp_client.close()
socket收发消息底层原理:数据从client的用户态内存中发出,传到内核态内存中,由操作系统指挥通过网卡发出到server。server端由操作系统控制经过网卡返回到用户态内存中;此时server中也发出数据到自己的内核态内存中,并由操作系统控制发到server内核态内存。从client发出的数据需要不为空,否则server一端处于一直等待接受状态。
图3 socket收发原理
6.服务端接受客户端1和客户端2发来的数据,使用try,except处理客户端1断开时抛出的异常
#服务端程序 from socket import * ip_port = ("192.168.1.4",8000) back_log = 5 buffer_size = 1024 tcp_server = socket(AF_INET,SOCK_STREAM) #买手机 tcp_server.bind(ip_port) #绑定手机卡 tcp_server.listen(back_log) #开机 while True: # print("服务端开始运行了") conn,addr = tcp_server.accept() #等待接听 #链接池,传送速率 print("双向链接是",conn) print('客户端地址:',addr) while True: try: data = conn.recv(buffer_size) #接听成功 print("客户端发来的消息",data.decode("utf-8")) conn.send(data.upper()) #发送消息 except: break conn.close() #通话完成 tcp_server.close() #关机 #客户端1程序 from socket import * ip_port = ("192.168.1.4",8000) back_log = 5 #指出有多少个SYN请求可以被存于堆栈中 buffer_size = 1024 #指定索引缓存区大小,决定索引处理的速度 tcp_client = socket(AF_INET,SOCK_STREAM) #开机 tcp_client.connect(ip_port) #连接 while True: msg = input(">>>") tcp_client.send(msg.encode("utf-8")) #发送数据到服务端 print("客户端已经发送消息") data = tcp_client.recv(buffer_size) #接受服务端数据 print("收到服务端发来的消息",data.decode("utf-8")) tcp_client.close() #客户端2程序 from socket import * ip_port = ("192.168.1.4",8000) back_log = 5 #指出有多少个SYN请求可以被存于堆栈中 buffer_size = 1024 #指定索引缓存区大小,决定索引处理的速度 tcp_client = socket(AF_INET,SOCK_STREAM) #开机 tcp_client.connect(ip_port) #连接 while True: msg = input(">>>") tcp_client.send(msg.encode("utf-8")) #发送数据到服务端 print("客户端2已经发送消息") data = tcp_client.recv(buffer_size) #接受服务端数据 print("收到服务端发来的消息",data.decode("utf-8")) tcp_client.close()
7.udp_socket通信协议
服务端基本逻辑和tcp_socket通信协议类似,包括导入socket模块和产生套接字对象,绑定IP和端口,收发消息
客户端基本逻辑,包括导入工作模块和产生套接字对象,收发消息
#服务端 from socket import * ip_port = ("192.168.1.4",8000) buffer_size = 1024 udp_server = socket(AF_INET,SOCK_DGRAM) udp_server.bind(ip_port) while True: data,addr = udp_server.recvfrom(buffer_size) #1024=字节数 print(data.decode("utf-8")) udp_server.sendto(data.upper(),addr) #客户端 from socket import * ip_port = ("192.168.1.4",8000) buffer_size = 1024 udp_client = socket(AF_INET,SOCK_DGRAM) while True: msg = input(">>>") udp_client.sendto(msg.encode("utf-8"),ip_port) #udp协议指定特定端口 data,addr = udp_client.recvfrom(buffer_size) print(data.decode("utf-8"))
基于udp_socket通信协议,实现ntp服务
#ntp服务端 from socket import * import time ip_port = ("192.168.1.4",8000) buffer_size = 1024 udp_server = socket(AF_INET,SOCK_DGRAM) udp_server.bind(ip_port) while True: try: data,addr = udp_server.recvfrom(buffer_size) #1024=字节数 recvfrom和sendto中间可多种操作逻辑 except Exception: continue print(data.decode("utf-8")) if not data: fmt = "%Y-%m-%d %X" else: fmt = data.decode("utf-8") back_time = time.strftime(fmt) udp_server.sendto(back_time.encode("utf-8"),addr) #ntp客户端 from socket import * ip_port = ("192.168.1.4",8000) buffer_size = 1024 udp_client = socket(AF_INET,SOCK_DGRAM) while True: msg = input(">>>") udp_client.sendto(msg.encode("utf-8"),ip_port) #udp协议指定特定端口 data,addr = udp_client.recvfrom(buffer_size) print("ntp服务器的标准时间是",data.decode("utf-8"))
8.基于TCP的远程通信
if判断处理server死循环
try-except处理client异常关闭
#SOCKET_TCP_SERVER from socket import * import subprocess ip_port = ('192.168.1.4',8000) back_log = 5 buffer_size = 1024 tcp_server = socket(AF_INET,SOCK_STREAM) tcp_server.bind(ip_port) tcp_server.listen(back_log) while True: conn,addr = tcp_server.accept() print("新的链接地址是",addr) while True: cmd = conn.recv(buffer_size) print("收到客户端的命令",cmd) #执行命令,得到命令的运行结果cmd_res try: res = subprocess.Popen(cmd.decode('gbk'),shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, stdin=subprocess.PIPE) err = res.stderr.read() if err: cmd_res = err else: cmd_res = res.stdout.read() conn.send(cmd_res) except Exception as e: print(e) break conn.close() #SOCKET_CLIENT_TCP from socket import * import subprocess ip_port = ("192.168.1.4",8000) back_log = 5 buffer_size = 8000 tcp_client = socket(AF_INET,SOCK_STREAM) tcp_client.connect(ip_port) while True: cmd = input(">>>").strip() if not cmd: continue if cmd == "quit": break tcp_client.send(cmd.encode("utf-8")) cmd_res = tcp_client.recv(buffer_size) print("命令的执行结果是:",cmd_res.decode("gbk")) tcp_client.close()
9.udp不粘包现象,但存在丢数据现象,所以接受池中接受字节数需要大于发送字节数
#不粘包_udp_server from socket import * ip_port = ("192.168.1.4",8000) buffer_size = 1024 udp_server = socket(AF_INET,SOCK_DGRAM) udp_server.bind(ip_port) data1 = udp_server.recvfrom(5) print("第1次",data1) data2 = udp_server.recvfrom(5) print("第2次",data2) data3 = udp_server.recvfrom(5) print("第3次",data3) #不粘包_udp_client from socket import * ip_port = ("192.168.1.4",8000) buffer_size = 1024 udp_client = socket(AF_INET,SOCK_DGRAM) udp_client.sendto(b"hello",ip_port) #发送数据报 udp_client.sendto(b"world",ip_port) udp_client.sendto(b"alex",ip_port)
二.计算机组成原理
1. 补码作用和运算步骤
补码可以在两数相加时,避免负数操作,直接运用加法运算 符号位分正负数 符号位=0,表示正数,补码是源码 符号位=1,表示负数,补码是源码取反加1
2. 操作码,地址码,BCD码
操作码:用来指明该指令需要完成的操作
地址码:用来指出该指令源操作数的地址
BCD码:binary code decimal
3. 11种寻址方式定义
1. 指令寻址:顺序寻址+跳跃寻址 2. 立即寻址:操作数本身设在指令字内,形式地址A不是操作数的地址,而是操作数本身,又称为立即数,不访问存储器 3. 直接寻址:指令字中的形式地址A就是操作数的真实地址EA,EA=A,不用专门计算操作数地址,对主存只访问一次。但A位数限制操作数寻址范围,先要修改A值才能改操作数地址 4. 隐含寻址:不直接给出操作数地址,操作数地址存在操作码或某个寄存器中,少一个地址利于缩短指令字长 5. 间接寻址:通过寻找操作数有效地址所在存储单元地址,有效地址由形式地址间接提供。扩大寻址范围,便于编制程序 6. 寄存器寻址:地址码字段直接指出寄存器编号,EA=R,操作数不在主存,寄存器寻址不访存 7. 寄存器间接寻址:有效地址存在寄存器,操作数存放在主存,比间接寻址少访问主存一次 8. 基址寻址:操作数有效地址EA等于指令字形式地址+基址寄存器内容 EA=A+BR 9. 变址寻址:有效地址EA等于指令字中的形式地址A与变址寄存器IX的内容相加,EA=A+IX 10. 相对寻址:相对寻址的有效地址是将程序计数器PC内容(当前指令地址)与指令字中的形式地址A相加而成,EA=PC+A,相对寻址常用于转移类指令。 11. 堆栈寻址:堆栈寻址可视为隐含寻址,操作数地址隐含在SP中,堆栈寻址本质是寄存器间接寻址。
4. 四种CPU控制类型
指令控制:控制程序的顺序执行
操作控制:完成每条指令所需的命令控制
时间控制:对各种操作加以时间上的控制
数据加工和处理中断:对数据进行算术运算和逻辑运算(数据加工)
5. 指令流水
断流指数据传输中断,做到不断流,需要控制好3个状态:
结构相关
数据相关
控制相关
6. 人类语音采样不失真条件
6.1采样频率≥2*原始信号频率
6.2接口:通信机器两个相同层次的实体叫做同层进程,它们之间的通信使用的各种约定统称协议,相邻层之间的约定称为接口。
6.3端口:接口电路中的一些寄存器,分为数据端口,控制端口,状态端口
6.4DMA:direct memory access
7. 计算机存储原理
7.1 二层次计算机系统:由虚拟机器M2(汇编语言机器)和实际机器M1构成,虚拟系统M2中运行应用软件,人为输入高级语言(汇编),由M2将汇编语言编译,以机器语言(与汇编语言一一对应)输入给M1,M1执行后将结果输出。
7.2 三层次计算机系统:原理与二层次系统类似,第三层为高级语言(如pascal,c,python),先将高级语言翻译成汇编语言,再由第二层次中的汇编语言执行命令,将其翻译成机器语言,输入计算机,输出结构
7.3 硬件研究主要对象:传统机器M1和微程序机器M0,软件研究主要对象:操作系统及以上各级虚拟机
7.4 计算机组成和计算机结构:组成主要指如何实现一系列的指令,结构指是否具备实现这一功能的能力,比如实现一个乘法指令,组成讨论的是使用一个乘法指令或者使用多个加法指令,结构讨论的是是否具备实现乘法结构的电路。
7.5 完成一条指令的三个阶段:取值,分析,执行。由存储器读出一条指令,分析该指令的操作数地址,同时指出该指令完成的操作。最后根据操作数地址和指令的操作码完成操作。比如要完成一个乘法指令,首先控制器将PC某一指令16位送入MAR中,命令其做读操作,接着将0号单元内容输入MDR中,MDR将0号单元内容送入控制器的IR中,完成一条取指令。接着经过CU分析,前6位是取数指令,接着将IR中后10位地址码送至MAR中,做读操作。该地址单元中存放x值,被送至MDR中,由MDR送至运算器的ACC中,完成执行过程,即完成一条取数指令操作,将第一条16位指令,通过CU读取操作码和地址码,将操作数x由MDR送至ACC完成指令1。接着PC将指令地址移位+1。将16位指令码送入MDR中,再由MDR送入IR中,CU分析操作码为乘法指令,CU向存储器发出读命令,读取后10位地址码地址数中的操作数a,由MDR送至MQ,CU最后向运算器发出乘法操作指令。
7.6 存储容量 = 存储单元个数(如32位) x 存储字长(1个存储字长16位,表示有2^16个存储单元,那么存储字长就是2^16)
7.7 波特率,比特率:异步通信中,波特率x有效数据位=比特率