Python对TCP/IP网络的支持,为不同类型的程序提供了很多有用的特性
1>半开放socket(Half-open sockets),它可以使你关闭一个方向上的通信
2>超时(Timeouts),它在等待了一定时间后,如果没有可以连接的网路则产生异常
3>传送字符串和标记字符串结束的技巧
4>网络字节命令,一般用于C-based协议的通信
5>广播(Broadcasts),它会同时向多个机器发送数据
6>使用IPV6,下一代互联网协议
7>绑定到特殊的地址或接口
8>使用poll和select同时查找多个不同的事件
超时:
eg:
#Echo Server with Timeouts --------- timeoutserver.py import socket,traceback host = '' port = 51423 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) s.bind((host,port)) s.listen(1) while True: try: clientsock,clientaddr = s.accept() except KeyboardInterrupt: raise except: traceback.print_exec() continue clientsock.settimeout(5) try: print "Got connection from",clientsock.getpeername() while True: data = clientsock.recv(4096) if not len(data): break clientsock.sendall(data) except (KeyboardInterrupt,SystemExit): raise except socket.timeout: pass except: traceback.print_exc() try: clientsock.close() except KeyboardInterrupt: raise except: traceback.print_exc()
网络字节:
eg:
#Network Byte Order ---- nbo.py import struct,sys def htons(num): return struct.pack('!H',num) def htonl(num): return struct.pack('!I',num); def ntohs(data): return struct.unpack('!H',data)[0] def ntohl(data): return struct.unpack('!I',data)[0] def sendstring(data): return htonl(len(data))+data print "Enter a string:" str = sys.stdin.readline().rstrip() print repr(sendstring(str))
广播:
服务器:
#UDP Broadcase Server --- bcastreceiver.py import socket,traceback host = '' port = 51423 s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) s.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1) s.bind((host,port)) while True: try: message,address =s.recvfrom(8192) print "Got data from ",address s.sendto("I am here",address) except (KeyboardInterrupt,SystemExit): raise except: traceback.print_exc()
客户端:
#Broadcast Sender ---- bcastsender.py import socket,sys dest = ('<broadcast>',51423) s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1) s.sendto("Hello",dest) print "Looking for replies; press Ctrl-C to stop." while True: (buf,address) = s.recvfrom(2048) if not len(buf): break print "Received from %s: %s" % (address,buf)
IPV6:
#getaddrinfo() display #Give a host and a port on the command line import socket,sys host,port = sys.argv[1:] results = socket.getaddrinfo(host,port,0,socket.SOCK_STREAM) for result in results: print "-"*60 if result[0] == socket.AF_INET: print "Family: AF_INET" elif result[0] == socket.AF_INET6: print "Family: AF_INET6" else: print "Family:",result[0] if result[1] == socket.SOCK_STREAM: print "Socket Type: SOCK_STREAM" elif result[1] == socket.SOCK_DGRAM: print "Socket Type: SOCK_DGRAM" print "Protocol:",result[2] print "Canonical Name:",result[3] print "Socket Address:",result[4]
Family参数:
#Connect Example with ipv6 Awareness ------------- ipv6connect.py import socket,sys def getaddrinfo_pref(host,port,socktype,familypreference=socket.AF_INET): """Given a host,port,and socktype (usually socket.SOCK_STREAM or socket.SOCK_DGRAM)), looks up information with both IPV4 and IPV6. If information is found corresponding to familypreference,it is returned. Otherwise,any information found is returned.The family preference defaults to IPV4(socket.AF_INET) but you could alse set it to socket.AF_INET6 for IPV6 The return value is the appropriate tuple returned from socket.getaddrinfo().""" results = socket.getaddrinfo(host,port,0,socktype) for result in results: if result[0] == familypreference: return result return results[0] host = sys.argv[1] port = 'http' c = getaddrinfo_pref(host,port,socket.SOCK_STREAM) print "Connecting to",c[4] s = socket.socket(c[0],c[1]) s.connect(c[4]) s.sendall("HEAD / HTTP/1.0 ") while True: buf = s.recv(4096) if not len(buf): break sys.stdout.write(buf)
绑定地址:
#Echo Server Bound to Specific Address #bindserver.py import socket,traceback host = '127.0.0.1' port = 51423 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) s.bind((host,port)) s.listen(1) while True: clientsock,clientaddr = s.accept() print "Got connection from",clientsock.getpeername() while True: data = clientsock.recv(4096) if not len(data): break clientsock.sendall(data) clientsock.close()
poll:
#Nonblocking I/O #pollclient.py import socket,sys,select port = 51423 host = 'localhost' spinsize = 10 spinpos = 0 spindir = 1 def spin(): global spinsize,spinpos,spindir spinstr = '.' * spinpos + '|' + '.'*(spinsize-spinpos-1) sys.stdout.write(''+spinstr+' ') sys.stdout.flush() spinpos += spindir if spinpos < 0: spindir = 1 spinpos = 1 elif spinpos >= spinsize: spinpos -= 2 spindir = -1 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect((host,port)) p = select.poll() p.register(s.fileno(),select.POLLIN | select.POLLERR | select.POLLHUP) while True: results = p.poll(50) if len(results): if results[0][1] == select.POLLIN: data = s.recv(4096) if not len(data): print ("Remove end closed connection ; exiting.") break sys.stdout.write("Received: " + data) sys.stdout.flush() else: print "Problem occurred exitng." sys.exit(0) spin()
select:
#selectclient.py import socket,sys,select port = 51423 host = 'localhost' spinsize = 10 spinpos = 0 spindir = 1 def spin(): global spinsize,spinpos,spindir spinstr = '.' * spinpos + '|' + '.' *(spinsize - spinpos -1) sys.stdout.write('' + spinstr +' ') sys.stdout.flush() spinpos += spindir if spinpos < 0: spindir = 1 spinpos = 1 elif spinpos >= spinsize: spinpos -= 2 spindir = -1 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect((host,port)) while True: infds,outfds,errfds = select.select([s],[],[s],0.05) if len(infds): #Normally,one would use something like "for fd in infds" here #We don't bother since there will only ever be a single file #descriptor there. data = s.recv(4096) if not len(data): print("Remote end closed connection; Exiting.") break sys.stdout.write("Received: " + data) sys.stdout.flush() if len(errfds): print "Problen occurred; exiting." sys.exit(0) spin()