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