Python异常处理、模块和包、网络编程

一、异常处理 

# try excpet
try:
    choice = int(input(">>>"))
    print(choice)
except ValueError:
    print("您输入的不是数字")


# 万能异常
# 所有的异常处理都用万能异常好不好?
# 具体的异常处理+万能异常:
    # 能够提前预料到的异常都应该用具体的异常去处理,剩下其他的异常用万能异常控制
    # 万能异常应该写在最后
try:
    choice = int(input(">>>"))
    print(choice)
except Exception:   # 不写Exception也是万能异常
    print("您输入的不是数字")


# try excpet as
# 可以显示具体的错误
try:
    choice = int(input(">>>"))
    print(choice)
except ValueError as e:
    print(e)
except Exception as e:  # 如果使用万能异常,一定要用as显示错误
    print(e)


# try excpet else
try:
    choice = int(input(">>>"))
    print(choice)
except ValueError: print('请输入一个数字')
except Exception as e: # 处理未知异常的所有异常
    print(e)
else:
    print('执行else了')     # 如果try语句中的代码都顺利的执行了,没有报错,那么执行else中的代码
finally:
    print('执行finally了')  # 无论如何都会执行


# try标准写法
try:
    pass  # 可能有问题的代码
except ValueError:  # 能预料到的错误
    pass
except Exception as e:print(e)  # 能处理所有的异常
else:pass          # try中的代码没有错误的时候执行
finally:pass       # 无论如何都会执行的


# 断言
# 如果断言失败则不执行断言下面的代码
assert 1==2

 

二、模块和包

# 模块总结
# 能不能导入模块 : sys.path
# 导入模块的顺序 : 内置模块 扩展模块 自定义模块
# 导入模块 : 相当于执行了这个模块,文件中的名字会被存储在一块独立的内存空间中
# 一个模块如果执行多次import,只会执行一次
# 模块之间不能发生循环引用。

# import
# 在全局创建了一个模块名,指向属于这个模块的命名空间
# 空间里存储了所有文件中的名字
# 起别名 import ... as ..
# 不推荐一行导入多个模块

# from import
# import后面的名字会出现在全局 ,相当于对独立命名空间中的一个引用
# from import 也支持 as语句 也支持 导入多个名字
# from import * 相当于导入所有名字,*和被导入模块__all__是互相影响的

#
# 定义:一组py文件组成的文件夹,在这个文件夹里有一个__init__.py 叫做包
# 导入一个模块相当于执行了模块中的代码
# 导入一个包相当于执行了__init__.py的代码
# 相对导入:以glance作为起始
# from ..cmd import manage
# manage.main()
# 绝对导入:用.或者..的方式最为起始(只能在一个包中使用,不能用于不同目录内)
# from glance.cmd import manage
# manage.main()

 

三、网络编程

# 为什么要有网络编程?
# 两个文件之间如何实现通信?
    #  基于文件通信--> 两个程序都在同一台机器上
    #  基于网络--> 两个不同机器上的程序


# 交换机是用于在一个局域网内的机器之间的通信
# 路由器是用于不同局域网之间的机器的通信
# arp协议:一台机器通过IP地址和交换机找到另一台机器的mac地址的过程

# ip地址能够找到网络中的唯一一台机器,临时的

# 如何在一台机器上精准的找到要和我通信的服务???
# 操作系统端口范围: 0-65535
# 在一台机器上 每一个服务所使用的端口不能相同

# 通过什么能够找到网络世界里的一个服务? ip+端口
# 两种通信协议
# TCP:(Transmission Control Protocol)可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。使用TCP的应用:Web浏览器;电子邮件、文件传输程序。
# UDP:(User Datagram Protocol)不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大努力服务,无拥塞控制。使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)
# 基于TCP协议的socket的server
# tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端
import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 9000)) # 把地址绑定到套接字
sk.listen()   # 监听链接

con, address = sk.accept()  # 接受客户端链接
msg = con.recv(1024).decode("utf-8") # 接收客户端信息
print(msg)  # 打印客户端信息
con.send("client说:你好".encode("utf-8"))  # 向客户端发送信息

con.close() # 关闭客户端套接字
sk.close() # 关闭服务器套接字(可选)


# 基于TCP协议的socket的client
import socket
sk = socket.socket()   # 创建客户套接字
sk.connect(("127.0.0.1", 9000))  # 尝试连接服务器
sk.send("server说:你好".encode("utf-8"))  # 给server发送消息
msg = sk.recv(1024).decode("utf-8")  # 接受server发来的消息
print(msg)
sk.close() # 关闭客户套接字
基于TCP协议的socket
# OSError: [WinError 10048] 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。
import socket
sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 就是它,在bind前加。端口重用
sk.bind(("127.0.0.1", 9000)) # 把地址绑定到套接字
sk.listen()   # 监听链接

con, address = sk.accept()  # 接受客户端链接
msg = con.recv(1024).decode("utf-8") # 接收客户端信息
print(msg)  # 打印客户端信息
con.send("client说:你好".encode("utf-8"))  # 向客户端发送信息

con.close() # 关闭客户端套接字
sk.close() # 关闭服务器套接字(可选)
OSError: [WinError 10048]处理方法
# 基于UDP协议的socket的server
# udp是无链接的,启动服务之后可以直接接受消息,不需要提前建立链接
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(("127.0.0.1", 9000))
msg, address = sk.recvfrom(1024)
print(address, msg.decode("utf-8"))
sk.sendto("你好".encode("utf-8"), address)
sk.close()

# 基于UDP协议的socket的client
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.sendto("你好".encode("utf-8"), ("127.0.0.1", 9000))
msg, address = sk.recvfrom(1024)
print(address, msg.decode("utf-8"))
sk.close()
基于UDP协议的socket
# QQ聊天
# server
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(("127.0.0.1", 9000))
while True:
    msg, address = sk.recvfrom(1024)
    print("%s[%s]:%s" % (address[0], address[1], msg.decode("utf-8")))
    to_msg = input(">>>:").strip()
    sk.sendto(to_msg.encode("utf-8"), address)

# client
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
while True:
    msg = input(">>>:")
    sk.sendto(msg.encode("utf-8"), ("127.0.0.1", 9000))
    msg, address = sk.recvfrom(1024)
    print("%s[%s]:%s" % (address[0], address[1], msg.decode("utf-8")))
QQ聊天
# server
import socket
import os
sk = socket.socket()
sk.bind(("127.0.0.1", 9000))
sk.listen()
while True:
    con, address = sk.accept()
    while True:
        msg = con.recv(1024).decode("utf-8")
        if msg.upper() == "Q":
            con.close()
            break
        ret = os.popen(msg).read()
        con.send(ret.encode("utf-8"))

# client
import socket
sk = socket.socket()
sk.connect(("127.0.0.1", 9000))
while True:
    cmd = input(">>>:")
    if not cmd:continue
    sk.send(cmd.encode("utf-8"))
    if cmd.upper() == "Q":break
    ret = sk.recv(1024).decode("utf-8")
    print(ret)
print("1")
sk.close()
执行远程命令-tcp
from socket import *
ip_port = ('127.0.0.1', 8080)

tcp_socket_server = socket()
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen()

conn, address = tcp_socket_server.accept()

data1 = conn.recv(10)
data2 = conn.recv(10)

print('----->', data1.decode('utf-8'))
print('----->', data2.decode('utf-8'))

conn.close()


# 粘包 接收方的缓存机制
# 接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)
#


# 黏包现象只发生在tcp协议中:
# 1.从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点。
# 2.实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的
粘包现象-server
# 粘包  发送方的缓存机制
# 发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)
import socket
BUFSIZE = 1024
ip_port = ('127.0.0.1', 8080)
s = socket.socket()
s.connect(ip_port)


s.send('hello'.encode('utf-8'))
s.send('egg'.encode('utf-8'))
s.close()
粘包现象-client
# 解决一些小数据在连续发送时候的粘包问题
import socket
import struct
sk = socket.socket()
sk.bind(("127.0.0.1", 9000))
sk.listen()
con, addr = sk.accept()

header_len_bytes = con.recv(4)                          # 接受客户端发来的struct类型长度为4的数据
header_len = struct.unpack("i", header_len_bytes)[0]    # unpack获取真实数据长度
print(con.recv(header_len))                             # 接受真实数据

header_len_bytes = con.recv(4)
header_len = struct.unpack("i", header_len_bytes)[0]
print(con.recv(header_len))

con.close()
sk.close()
解决粘包 初级版-server
# 解决一些小数据在连续发送时候的粘包问题
import socket
import struct
sk = socket.socket()
sk.connect(("127.0.0.1", 9000))


data1 = "aaaaaaaa"
header1 = struct.pack("i", len(data1))  # 使用struct把真实数据长度固定4的bytes类型
sk.send(header1)                        # 发送长度为4的bytes类型
sk.send(data1.encode("utf-8"))          # 发送真实的数据

data2 = "bbbbbbbb"
header2 = struct.pack("i", len(data2))
sk.send(header2)
sk.send(data2.encode("utf-8"))

sk.close()
解决粘包 初级版-client
# 解决粘包,高级版(主要解决大文件的传输)
import socket
import struct
import json
sk = socket.socket()
sk.bind(("127.0.0.1", 9000))
sk.listen()
con,addr = sk.accept()

header_struct = con.recv(4)      # 接受报头长度struct类型
header_len = struct.unpack("i", header_struct)[0]     # 获取unpack后的报头长度

header_str = con.recv(header_len).decode("utf-8")   # 获取字符串格式报头
header = json.loads(header_str)    # 反序列化字符串,获取字典格式的报头

recv_size = 0
with open(header["name"], "wb") as f:   # 循环接受真实数据
    while recv_size < header["size"]:
        line = con.recv(1024)
        f.write(line)
        recv_size += len(line)

con.close()
sk.close()
解决粘包 高级版-server
# 解决粘包,高级版(主要解决大文件的传输)
import socket
import json
import struct
import os

sk = socket.socket()
sk.connect(("127.0.0.1", 9000))

file_path = r"C:\Users\lanpa\Desktop\Python自动化21期\Python21\day8\课件\4.包.py"
header = {"name": os.path.basename(file_path),
          "size": os.path.getsize(file_path)}

header_json = json.dumps(header)    # 把字典转换成字符串格式
header_struck = struct.pack("i", len(header_json))  # 把字符串长度转换成struck类型固定长度为4的bytes类型

sk.send(header_struck)      # 发送header长度
sk.send(header_json.encode("utf-8"))        # 发送报头信息

with open(file_path, "rb") as f:    # 循环发送真实的数据
    for line in f:
        sk.send(line)
解决粘包 高级版-client

 

posted @ 2018-05-31 17:17  S.Curry  阅读(286)  评论(0编辑  收藏  举报