博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python的平凡之路(8)
阅读量:4577 次
发布时间:2019-06-08

本文共 7720 字,大约阅读时间需要 25 分钟。

(本文是对平凡之路(7)的补充等)

一、动态导入模块

import 
importlib
__import__
(
'import_lib.metaclass'
#这是解释器自己内部用的
#importlib.import_module('import_lib.metaclass') #与上面这句效果一样,官方建议用这个(亲测可用)

 

二、异常报错Raise使用

使用raise抛出异常

当程序出现错误,python会自动引发异常,也可以通过raise显示地引发异常。一旦执行了raise语句,raise后面的语句将不能执行。
演示raise用法
try:
     s = None
     if s is None:
         print "s 是空对象"
         raise NameError     #如果引发NameError异常,后面的代码将不能执行
     print len(s)
except TypeError:
     print "空对象没有长度"

 

三、断言的使用

用于检测某个条件表达式是否为真。assert语句又称为断言语句,即assert认为检测的表达式永远为真,if语句中的条件判断都可以使用assert语句检测。如果你非常确信某个你使用的列表中至少有一个元素,而你想要检验这一点,并且在它非真的时候引发一个错误,那么assert语句是应用在这种情形下的理想语句。当assert语句失败的时候,会引发一AssertionError 

断言1.py
#!/usr/bin/env python
#Author is wspikh
# -*- coding: encoding -*-
import sys
"""def k(x):
    x = x + 1
    return x
y= k(5)
#断言错误
assert type(y) is str
print(y)
 
断言2.py
#!/usr/bin/env python
#Author is wspikh
# -*- coding: encoding -*-
a = 23
print(a)
assert a < 30
a += 24
print(a)
assert a < 30

  

四、粘包相关

粘包:发送方发送两个字符串”hello”+”world”,接收方却一次性接收到了”helloworld”。
分包:发送方发送字符串”helloworld”,接收方却接收到了两个字符串”hello”和”world”。
解决粘包的问题:
1.服务端在发送数据之前,先把发送数据的长度告诉客户端,要发送多少数据,然后客户端根据这个数据的长度循环接收就OK
传输过程:
服务端:
    1.send  #数据长度
    4.recv  #收到确认信息,开始下一步发送
    send  #发送数据  
客户端 :
    2.recv #获取数据长度
    3.send #发送确认信息
    recv #循环接收  
socket-server端代码:
#解决粘包问题
send_data = bytes(send_data,encoding='utf-8') #编码成utf-8,字节,并把str转换为字节
ready_tag = 'Ready|%s' %len(send_data)
conn.send(bytes(ready_tag,encoding='utf-8'))
feedback = conn.recv(1024) #收到客户端发送过来的Start
feedback = str(feedback,encoding='utf-8') #把收到的feedback 转换为str
if feedback.startswith('Start'):
 conn.send(send_data)
socket-client端代码:#解决粘包的问题
ready_tag = s.recv(1024) # Ready|9999
ready_tag = str(ready_tag,encoding='utf-8')
 if ready_tag.startswith('Ready'):  # Ready|9999
        msg_size = int(ready_tag.split('|')[-1])
 start_tag = 'Start'
 s.send(bytes(start_tag,encoding='utf-8')) #给server发送Start,告诉server可以准备发送数据了
 recv_size = 0  #初始化数据大小
 recv_msg =b''
   while recv_size < msg_size:
        recv_data = s.recv(1024)
        recv_msg += recv_data
        recv_size += len(recv_data)
        print('MSG SIZE %s RECE SIZE %s' % (msg_size, recv_size))
    print(str(recv_msg,encoding='utf-8')) 

 

五、socket的进阶

计算密集型的用进程。
IO密集型的用进程。
xSocket语法及相关
1、Socket Families(地址簇)
socket.
AF_UNIX unix本机进程间通信 
socket.
AF_INET IPV4 
socket.
AF_INET6  IPV6
上面的这些内容代表地址簇,创建socket必须指定,默认为IPV4
2、Socket Types
socket.SOCK_STREAM  #for tcp
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通常仅限于高级用户或管理员运行的程序使用。
socket.SOCK_SEQPACKET #废弃了
3、Socket 方法
socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
Create a new socket using the given address family, socket type and protocol number. The address family should be  (the default), , ,  or . The socket type should be (the default), ,  or perhaps one of the other SOCK_ constants. The protocol number is usually zero and may be omitted or in the case where the address family is  the protocol should be one of CAN_RAW or . If fileno is specified, the other arguments are ignored, causing the socket with the specified file descriptor to return. Unlike , fileno will return the same socket and not a duplicate. This may help close a detached socket using .

socket.socketpair([family[, type[, proto]]])

Build a pair of connected socket objects using the given address family, socket type, and protocol number. Address family, socket type, and protocol number are as for the  function above. The default family is  if defined on the platform; otherwise, the default is .

()

socket.create_connection(address[, timeout[, source_address]])

Connect to a TCP service listening on the Internet address (a 2-tuple (host, port)), and return the socket object. This is a higher-level function than : if host is a non-numeric hostname, it will try to resolve it for both  and , and then try to connect to all possible addresses in turn until a connection succeeds. This makes it easy to write clients that are compatible to both IPv4 and IPv6.

Passing the optional timeout parameter will set the timeout on the socket instance before attempting to connect. If no timeout is supplied, the global default timeout setting returned by  is used.

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

socket.getaddrinfo(hostportfamily=0type=0proto=0flags=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(fileoffset=0count=None)

     发送文件 ,但目前多数情况下并无什么卵用。
 
SocketServer
利用SocketServer模块来实现网络客户端与服务器并发连接非阻塞通信。
首先,先了解下SocketServer模块中可供使用的类:
BaseServer:包含服务器的核心功能与混合(mix-in)类挂钩;这个类只用于派生,所以不会生成这个类的实例;可以考虑使用TCPServer和UDPServer。
TCPServer/UDPServer:基本的网络同步TCP/UDP服务器。
UnixStreamServer/ UnixDatagramServer:基本的基于文件同步TCP/UDP服务器。
ForkingMixIn/ ThreadingMixIn:实现了核心的进程化或线程化的功能;作为混合类,与服务器类一并使用以提供一些异步特性;这个类不会直接实例化。
ForkingTCPServer/ ForkingUDPServer:ForkingMixIn和TCPServer/UDPServer的组合。
BaseRequestHandler:包含处理服务请求的核心功能。这个类只用于派生,所以不会生成这个类的实例可以考虑使用StreamRequestHandler或DatagramRequestHandler。
StreamRequestHandler/ DatagramRequestHandler:用于TCP/UDP服务器的服务处理工具。

下面我们正式进入主题,这里我们采用StreamRequestHandler和ThreadingTCPServer来实现客户端与服务器并发连接非阻塞socket。

ThreadingTCPServer派生自ThreadingMixIn,主要实现核心的进程化合线程化功能。

StreamRequestHandler主要用于用于TCP/UDP服务器的服务处理工具。

一、创建SocketServerTCP服务端

[python]   
  1. #创建SocketServerTCP服务器:  
  2. import SocketServer  
  3. from SocketServer import StreamRequestHandler as SRH  
  4. from time import ctime  
  5.   
  6. host = 'xxx.xxx.xxx.xxx'  
  7. port = 9999  
  8. addr = (host,port)  
  9.   
  10. class Servers(SRH):  
  11.     def handle(self):  
  12.         print 'got connection from ',self.client_address  
  13.         self.wfile.write('connection %s:%s at %s succeed!' % (host,port,ctime()))  
  14.         while True:  
  15.             data = self.request.recv(1024)  
  16.             if not data:   
  17.                 break  
  18.             print data  
  19.             print "RECV from ", self.client_address[0]  
  20.             self.request.send(data)  
  21. print 'server is running....'  
  22. server = SocketServer.ThreadingTCPServer(addr,Servers)  
  23. server.serve_forever()   

二、创建SocketServerTCP客户端

[python]  

 
  1. from socket import *  
  2.   
  3. host = 'xxx.xxx.xxx.xxx'  
  4. port = 9999  
  5. bufsize = 1024  
  6. addr = (host,port)  
  7. client = socket(AF_INET,SOCK_STREAM)  
  8. client.connect(addr)  
  9. while True:  
  10.     data = raw_input()  
  11.     if not data or data=='exit':  
  12.         break  
  13.     client.send('%s\r\n' % data)  
  14.     data = client.recv(bufsize)  
  15.     if not data:  
  16.         break  
  17.     print data.strip()  
  18. client.close() 

 

      

转载于:https://www.cnblogs.com/wspkh/p/5865747.html

你可能感兴趣的文章
蒲公英App开发之检测新版本
查看>>
【安卓基础】倒计时按钮封装(验证码倒计时按钮)
查看>>
configparser模块
查看>>
SelectQueryBuilder的用法
查看>>
android的用户定位(一)
查看>>
creat-react-app搭建的项目中按需引入antd以及配置Less和如何修改antd的主题色
查看>>
IIS安装
查看>>
html块级元素和行级元素的区别和使用
查看>>
for循环嵌套
查看>>
寒冬夜行人
查看>>
poj1151 Atlantis
查看>>
HTML页面之间的参数传递
查看>>
java面试题集锦
查看>>
scikit-learn:4.2.3. Text feature extraction
查看>>
Spring Security构建Rest服务-0800-Spring Security图片验证码
查看>>
AE待整理
查看>>
java8中规范的四大函数式接口
查看>>
宝塔apache配置
查看>>
shell脚本中使用nohup执行命令不生效
查看>>
PHP 文件上传七牛云
查看>>