python exception handling - exception trap - thrown - assertion - custom exception -UDP communication application module -3 -socketserver

Exception trap

Exception: Program unpredictable error occurred during operation, and the error does not correspond to the processing mechanism, it will be shown in the form of abnormal

Impact: the entire program no longer function correctly

Structural abnormalities

The type of exception

NameError

Abnormal information

name 'safaf' is not defined

Abnormal position

'''
Traceback (most recent call last):
  File "E:/PyCharm 2019.1.3/ProjectFile/day010/day029/01 异常处理.py", line 1, in <module>
    safaf
'''

Unusual species

Grammatical errors

Bugs usually compiled into direct prompted, suggesting it should be directly addressed, is the basis of the general syntax errors appear too bad .

logical error

This error can be tolerated, logic errors can not be out of sight

To capture for the logical error exception handling mechanism can be used

Common types of errors

Common error types the reason
NameError Error name
SyntaxError Grammatical errors
keyError Key does not exist
ValueError Value error
IndexError Index error

How to avoid

Exception Handling

Use: at the top of the code may be a problem with the try to wrap you think

Note: inner try block as possible

Exception handling can be less with less, or where the error is not being given the wrong you do not know

Like the server, client break the link you need to use exception handling, you do not know when he will be disconnected

Exception handling using a template (try .. except .. else .. finally ..)

try:
    可能出错的代码
except 出错类型 as e:  # 将报错信息赋值给e
    错误的处理代码
except 出错类型2 as e:  # 将报错信息赋值给e
    错误的处理代码
except 出错类型3 as e:  # 将报错信息赋值给e
    错误的处理代码
    
# 或者 Exception直接捕获所有的
except Exception as e:  # 可以匹配所有的错误类型
    BaseException 是 Exception 的父类,也可以捕获所有类型
    错误的处理代码
else:
    当被检测的代码没有任何异常发生,才会执行这里面的语句
finally:
    无论被检测的代码有没有异常发生,都会在代码执行完后执行这里面的代码

Case

try:
    safaf
except NameError as e:
    print(e)
else:
    print("没有报错才会执行我哦~")
finally:
    print("管你报不报错,我都会执行的!")

# name 'safaf' is not defined
# 管你报不报错,我都会执行的!

try:
    print("我没错哦~")
except Exception as e:  # 捕捉所有异常
    print("管你啥错,我都抓了!")
else:
    print("没有报错才会执行我哦~")
finally:
    print("管你报不报错,我都会执行的!")
# 我没错哦~
# 没有报错才会执行我哦~
# 管你报不报错,我都会执行的!

supplement

Will stop immediately after an error code to run, to go with except in a comparison of the types of errors, match on the inside on the implementation of the code, the error did not match directly

Initiative thrown raise

if 'egon' == 'DSB':
    pass
else:
    raise TypeError('尽说大实话')  # 这一行就是报错的位置
    # raise 关键字就是用来主动抛出异常的

Assert assert

Assertion does not hold direct error

l = [1, 2, 3]
assert len(1) < 0  # assert 断言,预言,猜某个数据的状态,猜对了不影响代码执行,猜错了直接报错

Custom exception (inherited exception class)

Error types , a fact that the corresponding classes (abnormal splicing can customize format)

class MyError(BaseException):
    def __init__(self, msg):
        super().__init__()
        self.msg = msg
    
    def __str__(self):
        return f'----<{self.msg}>----'

raise MyError('自定义的异常')
# Traceback (most recent call last):
#   File "E:/PyCharm 2019.1.3/ProjectFile/day010/day029/test.py", line 15, in <module>
#     raise MyError('自定义的异常')
# __main__.MyError: ----<自定义的异常>----

UDP communication

UDP protocol called User Datagram Protocol

It is not a two-way channel, similar to text messaging (just hair, regardless of the other side has received, no other immediate response)

The program can be started UDP client and then start the server (client server to send data before no problem)

UDP类似于发短信

TCP类似于打电话,你一句我一句的

普通使用

服务端

import socket

server = socket.socket(type=socket.SOCK_DGRAM)  # type=socket.SOCK_DGRAM 指定成 UDP 协议  type=socket.SOCK_STREAM TCP协议(默认就是,不用指定)
server.bind(('127.0.0.1', 8080))

# UDP 不需要设置半连接池(server.listen(5)),也没有半连接池的概念
# UDP 没有双向通道,所以也不需要建立连接(conn, addr = server.accept())

# 直接就是通信循环

while True:  # 这里只需要直接通信(交互)即可
    data, addr = server.recvfrom(1024)
    print("数据:", data.decode('utf-8'))  # 客户端发来的消息
    print("地址:", addr)  # 客户端的地址

    re_msg = input("Please input your response msg:").strip()  # 会阻塞在这里,这里过了,才能发出信息,看到下一条信息
    server.sendto(re_msg.encode('utf-8'), addr)  # 向客户端发送消息


# 数据: hi
# 地址: ('127.0.0.1', 64821)
# Please input your response msg:o  hi
# 数据: hihihi
# 地址: ('127.0.0.1', 64823)
# Please input your response msg:xxixixi
# 数据: aha e
# 地址: ('127.0.0.1', 64828)
# Please input your response msg:emmm?
# 数据:
# 地址: ('127.0.0.1', 64828)
# Please input your response msg:adsa

客户端

import socket

client = socket.socket(type=socket.SOCK_DGRAM)

# UDP 不需要建立连接(client.connect(('127.0.0.1', 8080)))

server_addr = ('127.0.0.1', 8080)  # UDP sendto发消息时需要一个服务器的地址及端口号

while True:
    msg = input("Please input your msg:").strip()
    client.sendto(msg.encode('utf-8'), server_addr)  # 向服务器发送数据,要附带服务器端地址及端口(基于网络传输的数据都必须是二进制的)
    data, msg_from_server_addr = client.recvfrom(1024)  # 收到消息,且得到地址

    print("服务端发来的数据:", data.decode('utf-8'))
    print("服务器端的ip及端口", msg_from_server_addr)

# 窗口1
# Please input your msg:hi
# 服务端发来的数据: o  hi
# 服务器端的ip及端口 ('127.0.0.1', 8080)
# Please input your msg:

# 窗口2
# Please input your msg:hihihi
# 服务端发来的数据: xxixixi
# 服务器端的ip及端口 ('127.0.0.1', 8080)
# Please input your msg:

# 窗口3
# Please input your msg:aha e
#
# 服务端发来的数据: emmm?
# 服务器端的ip及端口 ('127.0.0.1', 8080)
# Please input your msg:服务端发来的数据: adsa
# 服务器端的ip及端口 ('127.0.0.1', 8080)
# Please input your msg:

TCP与UDP之间的区别

  1. UDP 允许发空数据,不会有影响
  2. UDP 直接启动客户端未启动服务端不会报错
  3. UDP 不会有粘包问题(自带报头)
  4. UDP 支持并发

服务端

import socket

server = socket.socket(type=socket.SOCK_DGRAM)

server.bind(('127.0.0.1', 8080))

while True:
    data, addr = server.recvfrom(1024)
    print(data.decode('utf-8'))

    server.sendto(data.upper(), addr)

客户端

import socket


client = socket.socket(type=socket.SOCK_DGRAM)

while True:

    msg = input(">>>:")
    # -------------------------------------------
    # 1.UDP 允许发空数据,不会有影响
    # -------------------------------------------
    # UDP自带报头,就算数据为空,另一端也能处理
    client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))  # 第二参数,目标服务器地址

    # -------------------------------------------
    # 2.UDP 直接启动客户端未启动服务端不会报错
    #   发数据找不到服务端也还是会报错
    # -------------------------------------------
    # 下面两行代码直接注释掉,服务端没启动,都不会报错,只管给服务器发(收没收到不管)
    # data, server_addr = client.recvfrom(1024)
    # print(data)

    # -------------------------------------------
    # 3.UDP 不会有粘包问题(自带报头)
    # -------------------------------------------
    # client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))
    # client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))
    # client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))
    #
    # server.sendto(data.upper(), addr)
    # server.sendto(data.upper(), addr)
    # server.sendto(data.upper(), addr)

    # -------------------------------------------
    # 4.UDP 支持并发
    #   TCP是保持连接,而UDP不需要保持连接
    #       与一个客户端断开连接才会和下一个客户端建立连接
    # -------------------------------------------

简易版的QQ

服务器端

import socket

server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(('127.0.0.1', 8080))

while True:
    data, client_addr = server.recvfrom(1024)
    print(data.decode('utf-8'))

    msg = input(">>>:").strip()
    server.sendto(msg.encode('utf-8'), client_addr)

# 来自star3的消息:helo
# >>>:hi
# 来自star2的消息:aha
# >>>:haa
# 来自star的消息:hello world
# >>>:ha
# 来自star2的消息:jason nnn
# >>>:jj

客户端1、2、3共用同一份代码

import socket

client = socket.socket(type=socket.SOCK_DGRAM)

username = 'star'
server_address = ('127.0.0.1', 8080)  # 指定一个发消息的目标服务器
while True:
    msg = input(">>>:").strip()

    msg = f'来自{username}的消息:{msg}'  # 是哪个用户名发出的数据不应该由这里传过去,用户可以随便改,实际意义不大
    '''
    user_dict = {
        "username1": (ip1 + port1),
        "username2": (ip2 + port2),
        "username3": (ip3 + port3),
    }
    # 可以在每个端都存这样一个对照表,根据ip与port就可以知道用户名了
    '''

    client.sendto(msg.encode('utf-8'), server_address)

    data, server_addr = client.recvfrom(1024)  # server_addr 收到消息的服务端地址

    print(data.decode('utf-8'))

# 各个窗口的控制台输入与输出
# >>>:helo
# hi
# >>>:

# >>>:aha
# haa
# >>>:jason nnn
# jj

# >>>:
# >>>:hello world
# ha
# >>>:

概念科普

  • 并发

看起来像同时运行(直接启动多个UDP客户端)(默认的UDP程序多开就是这个效果)

  • 并行

真正意义上的同时运行

socketserver模块科普

是给服务端用的(客户端还是用socket模块),可以保持连接

TCP模拟UDP实现并发

服务器端

import socketserver  # 文件名不要和模块冲突了,不然都不知道导哪个了


class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
        # 与客户端进行通信
        # print("来啦 老弟")
        while True:  # 需要保持通信(后续 client.send() 可没有附带服务器地址, connect 被关闭了)
            data = self.request.recv(1024)
            print(self.client_address)  # 客户端地址
            print(data.decode('utf-8'))
            self.request.send(data.upper())


if __name__ == '__main__':
    '''只要有客户端连接,会自动交给自定义类中的handle方法去处理'''
    server = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyServer)  # 创建一个基于TCP的对象
    server.serve_forever()  # 启动该服务对象

# ('127.0.0.1', 14327)
# dAddA
# ('127.0.0.1', 14326)
# ADD
# ('127.0.0.1', 14325)
# ADsafga

客户端

# TCP 实现UDP
import socket

client = socket.socket()
client.connect(('127.0.0.1', 8080))

while True:
    res = input(">>>:")
    client.send(res.encode('utf-8'))

    data = client.recv(1024)
    print(data.decode('utf-8'))


# 窗口1 控制台数据(输入与输出)
# >>>:dAddA
# DADDA
# >>>:

# 窗口2 控制台数据(输入与输出)
# >>>:ADD
# ADD
# >>>:

# 窗口1 控制台数据(输入与输出)
# >>>:ADsafga
# ADSAFGA
# >>>:

socketserver之UDP

服务器端

import socketserver  # 文件名不要和模块冲突了,不然都不知道导哪个了


class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
        # 与客户端进行通信
        # while True:  # UDP 不需要通信循环,每次 sendto 都有服务器的地址
        data, sock = self.request
        print(self.client_address)  # 客户端地址
        print(data.decode('utf-8'))
        sock.sendto(data.lower(), self.client_address)


if __name__ == '__main__':
    '''只要有客户端连接,会自动交给自定义类中的handle方法去处理'''
    server = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), MyServer)  # 创建一个基于UDP的对象
    server.serve_forever()  # 启动该服务对象

# 控制台打印的数据
# ('127.0.0.1', 52524)
# CLient2
# ('127.0.0.1', 52529)
# clet1
# ('127.0.0.1', 52529)
# CLienT1
# ('127.0.0.1', 54485)
# CLiEnt3

客户端

import socket

client = socket.socket(type=socket.SOCK_DGRAM)

server_addr = ('127.0.0.1', 8080)

while True:
    res = input(">>>:").strip()
    client.sendto(res.encode('utf-8'), server_addr)

    data, response_server_addr = client.recvfrom(1024)
    print(data.decode('utf-8'), response_server_addr)

# 窗口1 控制台数据(输入与输出)
# >>>:clIeNt1
# clet1 ('127.0.0.1', 8080)
# >>>:CLienT1
# client1 ('127.0.0.1', 8080)
# >>>:

# 窗口2 控制台数据(输入与输出)
# >>>:CLient2
# client2 ('127.0.0.1', 8080)
# >>>:

# 窗口1 控制台数据(输入与输出)
# >>>:CLiEnt3
# client3 ('127.0.0.1', 8080)
# >>>:

为什么UDP不用写通信循环

handle 是处理一次连接请求的,handle结束连接就断开了

UDP是不需要保持(双向)连接的,所以每次sendto 都是单个请求(都附带服务器端地址及端口),不能写通信循环(不然就拿着一个sendto 过来的数据循环打印了)

而TCP是基于双向通道通信的,handle结束后连接就断开了(再client.send() 这个连接状态就已经不存在了),所以TCP这边的服务端要写通信循环保持连接来多次通信

Guess you like

Origin www.cnblogs.com/suwanbin/p/11323276.html