标签:问题 需要 tin down break oar sage mes 阻塞
1 Python 高级网络操作 - Python Advanced Network Operations 2 3 Half Open Socket, 4 一个单向的 socket 被称为 half open socket, 即数据只能在一个方向上传输. 5 Half Open Socket 是通过在 socket 对象上调用 shutdown() 方法得到. 6 shutdown 接收一个 numeric 类型的参数, 7 0 - 表示调用之后禁止读 8 1 - 表示调用之后禁止写 9 2 - 表示调用之后禁止读和写 10 一旦关闭了某一个方向(读/写), socket 就不能再在该方向上被重新打开了. 11 shutdown()是累计的, 也就是调用 shutdown(0) 再调用 shutdown(1) 跟 12 直接调用一个 shutdown(2) 效果是一样的. 13 14 Half Open Socket 通常被应用在一下儿 3 种情形中, 15 1, 想要确保所有写好的数据都已经被传送出去. 16 调用 shutdown()的时候, 只有在缓存里面的数据都被成功发出去后方法才会有返回. 17 2, 用来 debug, 捕获潜在的异常/错误. 18 Half Open Socket 是捕获试图写一个不可写的 socket, 或者读一个不可读 19 的 socket 的异常的好方法. 20 3, 在程序是用了 fork() 或 多线程的时候, 用来防止其他进程/线程的某些操作. 21 22 socket 超时 - socket timeout 23 settimeout(seconds) 24 对一个 socket 对象调用 settimeout(secs) 方法后, 如果经过在 sces 秒之内什么都 25 没有发生(读/写), 则会产生一个 socket.timeout 异常, 链接机会断开, 26 例子, 27 ... ... 28 sock, addr = S.accept() 29 sock.settimeout(9) 30 ... ... 31 32 结束标识, 33 通过 socket 传输不确定长度的字符串的会遇到一个问题 - 不知道什么时候数据发送结束. 34 通常,有两种方法可以解决这个问题, 35 1, 通过指定字符串结束标识符(尾) 36 这个标识符通常是一个 NULL 字符(python - ‘\0‘) 或 newline 字符(python - ‘\n‘) 37 需要注意的问题是需要保证设定的结束符在所传输的内容中的‘唯一‘性. 38 2, 通过指定字符串长度指示符(首) 39 先发发送一个数字用来表示数据的长度, 接受方会根据这个数字长度的数据. 40 在网络上发送整形数据的时候,通常有一下儿两种选择, 41 a, 发送 ASCII 码(接收方收到后需要解码) 42 b, 直接发送 二进制 数, 一般位长是 16 或 32 位. 43 为了解决不同平台的二进制数据的编码方法不同的问题, 一种标准的二进制数据 44 表示法 - 网络字节顺序( Network Byte Order )被采纳. 在发送一个二进制数之前, 45 该二进制数被转换成 Network Byte Order; 接收方收到后, 在使用该数据之前做 46 ‘反向转换‘. 47 48 广播数据, 49 广播数据不能用 TCP 实现, 他多数是用 UDP 来实现的. 50 当接受方收到一个广播信息后, 系统内核会检查目的地的端口号信息. 如果系统上有一个在 listen 监听该端口 51 号的进程,则信息会被发送给该进程, 否者信息会被忽略掉. 52 例子, 53 发送方, 54 import socket 55 S = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP 56 S.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # 广播 broadcast 57 S.sendto("Hi there!",(‘<broadcast>‘, 12345)) # host = ‘<broadcast>‘ 58 59 while 1: 60 try: 61 data, addr = S.recvfrom(1024) 62 print("%s is connecting" % clientsocket.getpeername()) 63 except (KeyboardInterrupt,SystemExit) as e: 64 print(e) 65 raise 66 if not len(data): 67 break 68 print("Received message : %s from : %s",(data, addr)) 69 70 接受方, 71 import socket 72 73 S = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP 74 S.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 链接关闭后,端口立即可用 75 S.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # 广播 broadcast 76 S.bind((‘‘, 12345)) 77 78 while 1: 79 try: 80 mes, addr = S.recvfrom(8192) 81 print("Got message : %s from : %s" % (mes, addr)) 82 S.sendto("ACK", addr) # 回复不是广播 83 except (KeyboardInterrupt, SystemExit) as e: 84 print(e) 85 raise 86 87 通过 poll() 或 select() 实现事件通知, 88 通常, socket 上的 I/O 是阻塞的, 当一个操作(读/写)未结束,程序会阻塞. 89 在 nonblocking 模式中, 如果在没有完全准备好的 socket 对象调用 send() 或 recv() 方法 90 会触发 socket.error 异常. 在这种情况下, 就需要在调用 recv() 之前检查一下儿, socket 上 91 是不是有可以接受的 data. select() 和 poll() 就是满足检查需求的两个标准工具. 他们可以使 92 系统在某个 socket 上有事件发生的时候通知程序发生了什么, 从而在程序中进行有针对性的操作. 93 select() 接口是早起被普遍使用的, 但是在需要同时观察多个 socket 的事件的时候, 会变得很慢. 94 Windows 系统不支持 poll(), 必须使用 select(). 95 96 例子, 97 poll() 98 import socket, select 99 try: 100 S = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 101 except socket.error as e: 102 print("Error at creating socket : %s" % e) 103 104 try: 105 s.connect(("www.zzyzz.top", 80)) 106 except socket.gaierror as e: 107 print("Address related error : %s" % e) 108 except socket.error as e: 109 print("Connection error : %s" % e) 110 P = select.poll() 111 P.register(S.fileno(), select.POLLIN | select.POLLERR | select.POLLHUP) 112 # POLLIN 普通或优先级带数据可读 113 # POLLERR 发生错误 114 # POLLHUP 对方描述符挂起 115 # POLLRDNORM 普通数据可读 116 # POLLRDBAND 优先级带数据可读 117 # POLLPRI 高优先级数据可读 118 # POLLOUT 普通数据可写 119 # POLLWRNORM 普通数据可写 120 # POLLWRBAND 优先级带数据可写 121 # POLLNVAL 描述字不是一个打开的文件 122 123 while 1: 124 res = P.poll(100) # poll 间隔 100 毫秒 125 if len(res): 126 if res[0][1] == select.POLLIN: 127 data = S.recv(1024) 128 if not len(data): 129 print("Connection closed") 130 break 131 print("Received data : %s" % data) 132 else: 133 print("Errors occurred") 134 break 135 136 select() 来解决 I/O 阻塞 137 select(rlist, wlist, elist[, timeout]) 138 rlist - ‘读‘ 的文件对象列表 139 wlist - ‘写‘ 的文件对象列表 140 elist - ‘错误‘ 的文件对象列表 141 timeout - 可选参数, 接收浮点类型, 指明超时的时间(秒) 142 143 select() 方法的调用返回 3 个tuple, 每一个 tuple 都是一个对象列表, 顺序对应参数顺序. 144 145 import socket, select 146 try: 147 S = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 148 except socket.error as e: 149 print("Error at creating socket : %s" % e) 150 151 try: 152 s.connect(("www.zzyzz.top", 80)) 153 except socket.gaierror as e: 154 print("Address related error : %s" % e) 155 except socket.error as e: 156 print("Connection error : %s" % e) 157 158 while 1: 159 infds, outfds, errfds = select.select([S],[],[S],0.05) 160 if len(infds): 161 data = S.recv(1024) 162 if not len(data): 163 print("Connection closed") 164 break 165 print("Received data : %s" % data) 166 if len(errfds): 167 print("Errors occurred") 168 break
Python 高级网络操作 - Python Advanced Network Operations
标签:问题 需要 tin down break oar sage mes 阻塞
原文地址:http://www.cnblogs.com/zzyzz/p/7994036.html