读书人

python模块引见- socket(3)

发布时间: 2013-03-17 13:48:31 作者: rapoo

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

读书人网 >perl python

热点推荐