高级网络操作

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\n\n")

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('\r'+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 ("\rRemove end closed connection ; exiting.")
                break
            sys.stdout.write("\rReceived: " + data)
            sys.stdout.flush()

        else:
            print "\rProblem 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('\r' + 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("\rRemote end closed connection; Exiting.")
            break
        sys.stdout.write("\rReceived: " + data)
        sys.stdout.flush()

    if len(errfds):
        print "\rProblen occurred; exiting."
        sys.exit(0)
    spin()

 

 

 

posted @ 2013-09-04 17:39  lfsblack  阅读(421)  评论(0编辑  收藏  举报