python自动化编程-第七天 异常 socket

目录

  • 一、异常处理
  • 1、异常捕获语法
  • 2、常见异常
  • 3、主动触发异常
  • 4、自定义异常
  • 5、始终抓不到的错误
  • 二、断言
  • 三、socket编程
  • 1、socket简介
  • 2、socket参数介绍
  • 3、socket简单实例
  • 4、socket 实现多连接处理

一、异常处理

python通过产生异常来指明发生错误或异常文件;

1、异常捕获语法

异常捕获语法:

try:
    code
# except excepition_group1,variable1: # in python 2.7
except excepition_group1 as variable1:   # in python 3.0
    except_suite1
……
except excepition_groupN as variableN:
    except_suiteN
else:  #没有捕获到异常才会执行
    else_suite
finally:  #不管有没有异常都会执行
    finally_suite

至少包含一个except块,但是else和finally都是可选的;当try下面的code正常执行完成时,会执行else语句;如果捕获到异常,else就不会执行了;但是不管有没有异常,finally语句都是会执行的

每个except分支的异常组都可以是一个单独的异常,或者一个异常元组;
如果try语句中发生异常,那么每个except分支会顺序尝试执行,因此Exception异常应该写在最后一个except上;

2、常见异常

AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError 语法错误
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的

dic = ["wupeiqi", 'alex']
try:
    dic[10]
except IndexError, e:
    print e
dic = {'k1':'v1'}
try:
    dic['k20']
except KeyError, e:
    print e
s1 = 'hello'
try:
    int(s1)
except ValueError, e:
    print e

异常类只能用来处理指定的异常情况,如果非指定异常则无法处理。

3、主动触发异常

try:
    raise Exception('错误了。。。') #触发异常
except Exception,e:
    print e

4、自定义异常

class var_aaException(Exception):
 
    def __init__(self, msg):
        self.message = msg
 
    def __str__(self):
        return self.message
 
try:
    raise var_aaException('我的异常')
except var_aaException as e:
    print e

5、始终抓不到的错误

try:
    pass
except IndentationError:
    pass
except SyntaxError:
    pass

二、断言

断言语法:

assert data is str
#判断 变量 data 是一个字符串,如果是字符串则程序继续运行,否则就会报一个断言错误;

>>> assert type(data) is str
>>> assert type(data) is int
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError
>>>

有时可以充当if语句使用,然后通过try语句抓取错误;
断言可以 判断数据类型,也可以做成员判断,一旦结果为False,则报AssertionError错误。

三、socket编程

1、socket简介

网络套接字是通过计算机网络连接的端点。如今,大多数计算机之间的通信都是基于Internet协议;因此,大多数network socket都是internet socket。更准确地说,套接字是一个句柄(抽象引用),本地程序可以传递给网络应用程序编程接口(API)来使用连接,例如“send this data on this socket”。

例如,要发送“Hello, world!”,通过TCP到主机的80端口(地址为1.2.3.4),可能会得到一个socket,将它连接到远程主机,发送字符串,然后关闭套接字。

socket API
一个 socket API是应用程序编程接口(API), 通常由操作系统提供, 允许应用程序控制和使用网络套接字。Internet socket api 通常基于伯克利套接字标准。在伯克利插座标准中, socket是文件描述符(文件句柄) 的一种形式, 原因是Unix 哲学"一切都是文件", 以及socket和文件之间的类比: 既可以读取、写入,又可以打开和关闭.

socket address
一个 socket address是IP地址和端口号的组合, 就像电话连接的一端是电话号码和特定扩展的组合。套接字不需要地址 (例如只发送数据), 但是如果程序绑定一个套接字到地址, 则可以使用套接字接收发送到该地址的数据。基于此地址, internet 套接字将传入数据包传递到相应的应用程序进程或线程.

socket Families (地址簇)

socket.AF_UNIX unix本机进程间通信

socket.AF_INET IPV4

socket.AF_INET6 IPV6

Socket Types

socket. SOCK_STREAM #for tcp,python3中默认
socket. SOCK_DGRAM #for udp
socket. SOCK_RAW #原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
socket. SOCK_RDM #是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。

2、socket参数介绍

socket. socket (family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None) 必会

使用给定的地址系列、套接字类型和协议号创建新的套接字。地址族应为 AF_INET (默认), AF_INET6, AF_UNIX, AF_CAN 或 AF_RDS.套接字类型应为SOCK_STREAM (默认值)、 SOCK_DGRAM、 SOCK_RAW 或可能是其他SOCK_常量之一。协议编号通常为零, 可能会被省略, 或者在地址族为 AF_CAN 的情况下, 协议应该是CAN_RAW或 CAN_BCM中的一个。如果指定了fileno , 则忽略其他参数, 从而使带有指定文件描述符的套接字返回。与 socket.fromfd()不同, fileno将返回相同的套接字而不是重复的插槽。这可能有助于关闭使用 socket.close() 的分离的套接字.

socket.socketpair([家庭[,类型[,原始]]])

使用给定的地址族、套接字类型和协议号生成一对连接的套接字对象。地址族、套接字类型和协议号与上面的 socket() 功能相同。如果在平台上定义了默认系列, 则为 AF_UNIX ;否则, 默认值为 AF_INET .

socket.create_connection(地址[,超时[, source_address]])

连接到在 Internet 上侦听的 TCP 服务地址(2 元组(host, port)), 并返回套接字对象。这比 socket.connect(): 如果主机是非数字主机名, 它将尝试为 AF_INET 和 AF_INET6 , 然后尝试依次连接到所有可能的地址, 直到连接成功为止。这使得编写兼容 IPv4 和 IPv6 的客户端变得很容易。

在尝试连接之前, 传递可选的超时参数将在套接字实例上设置超时。如果未提供超时, 则使用 getdefaulttimeout() 返回的全局默认超时设置。

If supplied, source_address must be a 2-tuple (host, port) for the socket to b ind to as its source address before connecting. If host or port are ‘’ or 0 respectively the OS default behavior will be used.

socket. getaddrinfo (host, port, family=0, type=0, proto=0, flags=0 ) #获取要连接的对端主机地址 必会

sk.bind(address) 必会

s.bind(address) 将套接字绑定到地址。 address地址的格式取决于地址族。 在AF_INET下,以元组(host,port)的形式表示地址。

sk.listen(backlog) 必会

开始监听传入连接。 backlog指定在拒绝连接之前,可以挂起的最大连接数量。

backlog等于5,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的连接个数最大为5
这个值不能无限大,因为要在内核中维护连接队列

sk.setblocking(bool) 必会

是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。

sk.accept() 必会

接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。 address是连接客户端的地址。

接收TCP 客户的连接(阻塞式)等待连接的到来

sk.connect(address) 必会

连接到address处的套接字。 一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。

sk.connect_ex(address)

同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码,例如:10061

sk.close() 必会

关闭套接字

sk.recv(bufsize[,flag]) 必会

接受套接字的数据。 数据以字符串形式返回,bufsize指定最多可以接收的数量。 flag提供有关消息的其他信息,通常可以忽略。

sk.recvfrom(bufsize[.flag])

与recv()类似,但返回值是(data,address)。 其中data是包含接收数据的字符串,address是发送数据的套接字地址。

sk.send(string[,flag]) 必会

将string中的数据发送到连接的套接字。 返回值是要发送的字节数量,该数量可能小于string的字节大小。 即:可能未将指定内容全部发送。

sk.sendall(string[,flag]) 必会

将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。 成功返回None,失败则抛出异常。

内部通过递归调用send,将所有内容发送出去。

sk.sendto(string[,flag],address)

将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。 返回值是发送的字节数。 该函数主要用于UDP协议。

sk.settimeout(timeout) 必会

设置套接字操作的超时期,timeout是一个浮点数,单位是秒。 值为None表示没有超时期。 一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s )

sk.getpeername() 必会

返回连接套接字的远程地址。 返回值通常是元组(ipaddr,port)。

sk.getsockname()

返回套接字自己的地址。 通常是一个元组(ipaddr,port)

sk.fileno()

套接字的文件描述符

socket. sendfile (file, offset=0, count=None)

发送文件 ,但目前多数情况下并无什么卵用。

3、socket简单实例

伪代码表示:

#客户端
import socket


client = socket.socket()   #声明socket类型,同时生成socket链接对象,默认就是tcp/ip

client.connect(('localhost',6969))

client.send(b'hello world')  #在python3中只能发byte类型

client.send(msg.encode('utf-8'))  #byte只能去接收ascii码的类型,要想传递中文,则需要encode成ascii

data = client.recv(1024) #1024字节
print('recv:',data)

client.close()
#服务器端
import socket

server = socket.socket()

server.bind(('localhost',6969)) #绑定要监听的端口

server.listen(5)  #监听端口,
# 最多允许挂起多少个连接,就是允许多少人排队,此处测试不出来是因为已经开始循环,不会检测listen,一般写5个,不要多于10个

print('我要等待数据传入')
conn, addr = server.accept()  # waiting 等数据传输进来

print(conn, addr)
    # conn就是客户端连过来而在服务器端为其生成的一个链接实例
print('数据来了')

data = conn.recv(2014)  #单位字节
print('recv:',data.decode())

conn.send(data.upper())

server.close()

上面的代码的有一个问题, 就是服务器端运行起来后, 接收了一次客户端的data就会退出了。。。, 但实际场景中,一个连接建立起来后,可能要进行多次往返的通信。

代码修改如下:

#客户端
import socket

client = socket.socket()   #声明socket类型,同时生成socket链接对象,默认就是tcp/ip

client.connect(('localhost',6969))

# client.send(b'hello world')  #在python3中只能发byte类型

while True:
    msg = input('>>:').strip()  #不能发空,发了空的话服务器就收不到信息,以为你在发送数据,所以会卡主

    if len(msg) == 0:continue

    client.send(msg.encode('utf-8'))  #byte只能去接收ascii码的类型,要想传递中文,则需要encode成ascii

    data = client.recv(1024) #1024字节
    print('recv:',data)

client.close()
#服务器端
import socket

server = socket.socket()

server.bind(('localhost',6969)) #绑定要监听的端口

server.listen(5)  #监听端口,
# 最多允许挂起多少个连接,就是允许多少人排队,此处测试不出来是因为已经开始循环,不会检测listen,一般写5个,不要多于10个

print('我要等待数据传入')

conn, addr = server.accept()  # waiting 等数据传输进来

print(conn, addr)
# conn就是客户端连过来而在服务器端为其生成的一个链接实例
print('数据来了')

while True:

    data = conn.recv(1024)  #单位字节

    if not data:break
    print('recv:',data.decode())

    conn.send(data.upper())

server.close()

此时就可以实现一个用户登录以后多次的数据传输,但是不能实现多用户连接

4、socket 实现多连接处理

服务器端代码修改如下

#服务器端
import socket

server = socket.socket()

server.bind(('localhost',6969)) #绑定要监听的端口

server.listen(5)  #监听端口,
# 最多允许挂起多少个连接,就是允许多少人排队,此处测试不出来是因为已经开始循环,不会检测listen,一般写5个,不要多于10个

print('我要等待数据传入')

while True:
    conn, addr = server.accept()  # waiting 等数据传输进来

    print(conn, addr)
    # conn就是客户端连过来而在服务器端为其生成的一个链接实例
    print('数据来了')

    while True:

        data = conn.recv(2014)  #单位字节


        if not data:break
        print('recv:',data.decode())

        conn.send(data.upper())

server.close()

此时,虽然可以同时连接多个,但是只能给一个用户提供服务,其他用户的排队等待;