首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > perl python >

python模块引见- socket(3)

2013-03-17 
python模块介绍- socket(3)11.1.4 unix域套接字从程序员的角度来看,UNIX域套接字和TCP/IP套接字有两个本质

python模块介绍- socket(3)
11.1.4 unix域套接字

从程序员的角度来看,UNIX域套接字和TCP/IP套接字有两个本质的区别:首先,套接字的地址是文件系统路径,而不是一个包含服务器名称和端口元组。其次,在文件系统中创建的表示套接字节点在套接字关闭以后永久存在,服务器启动时需要删除这些文件。

Echo服务器端:

importsocket

importsys

importos

 

server_address= './uds_socket'

 

#Make sure the socket does not already exist

try:

    os.unlink(server_address)

exceptOSError:

    if os.path.exists(server_address):

        raise

 

#Create a UDS socket

sock= socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)

 

#Bind the socket to the address

print>>sys.stderr, 'starting up on %s' % server_address

sock.bind(server_address)

 

#Listen for incoming connections

sock.listen(1)

 

whileTrue:

    # Wait for a connection

    print >>sys.stderr, 'waiting for aconnection'

    connection, client_address = sock.accept()

    try:

        print >>sys.stderr, 'connectionfrom', client_address

 

        # Receive the data in small chunks andretransmit it

        while True:

            data = connection.recv(16)

            print >>sys.stderr, 'received"%s"' % data

            if data:

                print >>sys.stderr,'sending data back to the client'

                connection.sendall(data)

            else:

                print >>sys.stderr, 'nodata from', client_address

                break

           

    finally:

        # Clean up the connection

        connection.close()

 

      echo客户端:

      import socket

importsys

 

#Create a UDS socket

sock= socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)

 

#Connect the socket to the port where the server is listening

server_address= './uds_socket'

print>>sys.stderr, 'connecting to %s' % server_address

try:

    sock.connect(server_address)

exceptsocket.error, msg:

    print >>sys.stderr, msg

    sys.exit(1)

 

try:

   

    # Send data

    message = 'This is the message.  It will be repeated.'

    print >>sys.stderr, 'sending"%s"' % message

    sock.sendall(message)

 

    amount_received = 0

    amount_expected = len(message)

   

    while amount_received < amount_expected:

        data = sock.recv(16)

        amount_received += len(data)

        print >>sys.stderr, 'received"%s"' % data

 

finally:

    print >>sys.stderr, 'closing socket'

    sock.close()

执行结果和前面的类似,不再赘述。实际使用需要注意uds_socket的文件权限。

 

Socketpair可以建立一对UDS套接字并使其互相通信。

importsocket

importos

 

parent,child = socket.socketpair()

 

pid= os.fork()

 

ifpid:

    print 'in parent, sending message'

    child.close()

    parent.sendall('ping')

    response = parent.recv(1024)

    print 'response from child:', response

    parent.close()

 

else:

    print 'in child, waiting for message'

    parent.close()

    message = child.recv(1024)

    print 'message from parent:', message

    child.sendall('pong')

    child.close()

注意这里其实只有一个程序,但是相当于2个程序在执行,搞异步,这个东东还是很有意思的。

执行结果:

# pythonsocket_socketpair.py

in parent,sending message

in child,waiting for message

message fromparent: ping

response fromchild: pong

 

11.1.5 多播

              多播地址:224.0.0.0- 230.255.255.255

我们这边把多播的发送端配置成多播服务器,实际上是UDP的客户端,步骤如下:1,创建socket.socket(socket.AF_INET,socket.SOCK_DGRAM),设定地址族和套接字类型;2,设定socket:sock.setsockopt(socket.IPPROTO_IP,socket.IP_MULTICAST_TTL, 1);3,发送数据:sent= sock.sendto(message, multicast_group),接收数据:data,server = sock.recvfrom(16)。

socket.setsockopt(level,optname, value)

设置socket选项(见Unix手册页setsockopt(2))。符号常量被定义在socket模块(SO_*等)。该值可以是一个整数或一个表示buffer的字符串。在后一种情况下需要struct来转换。

import socket

#importstruct

import sys

 

message ='Welcome to adva mutli center:  ip :224.3.29.71, port 10000'

multicast_group= ('224.3.29.71', 10000)

 

# Create thedatagram socket

sock =socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

 

# Set atimeout so the socket does not block indefinitely when trying

# to receivedata.

sock.settimeout(0.1)

 

# Set thetime-to-live for messages to 1 so they do not go past the

# localnetwork segment.

#ttl =struct.pack('b', 1)

sock.setsockopt(socket.IPPROTO_IP,socket.IP_MULTICAST_TTL, 1)

 

while True:

    # Send data to the multicast group

    print >>sys.stderr, 'sending"%s"' % message

    sent = sock.sendto(message,multicast_group)

   

    # Look for responses from all recipients

    while True:

        try:

            data, server = sock.recvfrom(16)

        except socket.timeout:

            break

        else:

                print >>sys.stderr, 'received"%s" from %s' % \

                    (data, server)  

else:

    print >>sys.stderr, 'closing socket'

    sock.close()

 

我们这边把多播的接收端配置成多播客户端端, 实际上是UDP的服务器端,步骤如下:1,创建socket.socket(socket.AF_INET,socket.SOCK_DGRAM),设定地址族和套接字类型;2,sock.bind(server_address),设定socket:sock.setsockopt(socket.IPPROTO_IP,socket.IP_MULTICAST_TTL, 1);3,接收数据:data,server = sock.recvfrom(16)。

发送数据:sent= sock.sendto(message, multicast_group),

import socket

import struct

import sys

 

multicast_group= '224.3.29.71'

server_address= ('', 10000)

 

# Create thesocket

sock =socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

 

# Bind to theserver address

sock.bind(server_address)

 

# Tell theoperating system to add the socket to the multicast group

# on allinterfaces.

group =socket.inet_aton(multicast_group)

mreq =struct.pack('4sL', group, socket.INADDR_ANY)

sock.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP, mreq)

 

#Receive/respond loop

while True:

    print >>sys.stderr, '\nwaiting toreceive message'

    data, address = sock.recvfrom(1024)

   

    print >>sys.stderr, 'received %sbytes from %s' % \

        (len(data), address)

    print >>sys.stderr, data

 

    print >>sys.stderr, 'sendingacknowledgement to', address

    sock.sendto('ack', address)

执行结果:

./socket_multicast_sender.py

sending"Welcome to adva mutli center:  ip :224.3.29.71, port 10000"

received"ack" from ('172.23.191.217', 10000)

received"ack" from ('172.23.191.218', 10000)

sending"Welcome to adva mutli center:  ip :224.3.29.71, port 10000"

received"ack" from ('172.23.191.217', 10000)

received"ack" from ('172.23.191.218', 10000)

 

#./socket_multicast_receiver.py

 

waiting toreceive message

received 59bytes from ('172.23.191.217', 56125)

Welcome toadva mutli center:  ip : 224.3.29.71,port 10000

sendingacknowledgement to ('172.23.191.217', 56125)

 

waiting toreceive message

received 59bytes from ('172.23.191.217', 56125)

Welcome toadva mutli center:  ip : 224.3.29.71,port 10000

sendingacknowledgement to ('172.23.191.217', 56125)

 

#./socket_multicast_receiver.py

 

waiting toreceive message

received 59bytes from ('172.23.191.217', 56125)

Welcome toadva mutli center:  ip : 224.3.29.71,port 10000

sendingacknowledgement to ('172.23.191.217', 56125)

 

waiting toreceive message

received 59bytes from ('172.23.191.217', 56125)

Welcome toadva mutli center:  ip : 224.3.29.71,port 10000

sendingacknowledgement to ('172.23.191.217', 56125)

 

参考资料:

Multicast(http://en.wikipedia.org/wiki/Multicast) Wikipedia article describing

technicaldetails of multicasting.

IP Multicast(http://en.wikipedia.org/wiki/IP_multicast) Wikipedia article about IP

multicasting,with information about addressing.

11.1.6 发送二进制数据

              服务器端:

importbinascii

importsocket

importstruct

importsys

 

#Create a TCP/IP socket

sock= socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_address= ('localhost', 10000)

sock.bind(server_address)

sock.listen(1)

 

unpacker= struct.Struct('I 2s f')

 

whileTrue:

    print >>sys.stderr, '\nwaiting for aconnection'

    connection, client_address = sock.accept()

    try:

        data = connection.recv(unpacker.size)

        print >>sys.stderr, 'received %r'% binascii.hexlify(data)

 

        unpacked_data = unpacker.unpack(data)

        print >>sys.stderr, 'unpacked:',unpacked_data

       

    finally:

        connection.close()

客户端:

importbinascii

importsocket

importstruct

importsys

 

#Create a TCP/IP socket

sock= socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_address= ('localhost', 10000)

sock.connect(server_address)

 

values= (1, 'ab', 2.7)

packer= struct.Struct('I 2s f')

packed_data= packer.pack(*values)

 

print'values =', values

 

try:

   

    # Send data

    print >>sys.stderr, 'sending %r' %binascii.hexlify(packed_data)

    sock.sendall(packed_data)

 

finally:

    print >>sys.stderr, 'closing socket'

sock.close()

执行结果:

# ./socket_binary_server.py

 

waiting for a connection

received '0100000061620000cdcc2c40'

unpacked: (1, 'ab', 2.7000000476837158)

 

waiting for a connection

# ./socket_binary_client.py

values = (1, 'ab', 2.7000000000000002)

sending '0100000061620000cdcc2c40'

closing socket

这里传送的是一个整数,两个字符的字符串和浮点数。浮点数在传送过程中可能会丢失一些精度。对于整数,有可能转为文本再传送比struct更有效。比如整数1作为文本,只占用一个字节,作为struct的整数占4个字节。

11.1.7非阻塞通信和超时


默认情况下,socket发送或接收数据块是阻塞的,socket准备就绪之前,程序会停止执行。这种形式的I /O操作是容易理解,不过低效且双方都等待发送或接收数据时容易死锁。

有几种方法可以解决此问题的。一种方法是使用一个单独的线程与每个socket通信。这会引入其他的复杂性。另一种选择是让socket不阻塞程序立即返回setblocking()方法来改变socket的阻塞标志。默认值1,这意味着阻止。传递的值0会关闭阻塞。如果socket非阻塞且数据没有准备好,就会报socket.error。一个折衷的办法是设置通过settimeout()设置套接字操作的超时值,超时时产生timeout异常。

参考资料:

socket (http://docs.python.org/library/socket.html) Thestandard library documentation

for this module.

Socket Programming HOWTO(http://docs.python.org/howto/sockets.html) An

instructional guide by Gordon McMillan, included in thestandard library

documentation.

select (page 594) Testing a socket to see if it is ready forreading or writing for nonblocking

I/O.

SocketServer (page 609) Framework for creating networkservers.

urllib (page 651) and urllib2 (page 667) Most network clientsshould use the

more convenient libraries for accessing remote resourcesthrough a URL.

asyncore (page 619) and asynchat (page 629) Frameworks forasynchronous

communication.

Unix Network Programming, Volume 1: The Sockets NetworkingAPI, 3/E By

W. Richard Stevens, Bill Fenner, and Andrew M. Rudoff.Published by

Addison-Wesley Professional, 2004. ISBN-10: 0131411551

热点排行