Python を使ったプログラム間通信の仕方の勉強の続き.

前回は UDP を使って,通信相手をみつけ,その後,TCP を使って相手と通信を行うところまでたどり着いた.

しかし,情報を受け取るために socket の recv() 関数を使っていたので,複数パケットに分割して送られてきた情報をまとめて受信,ということができなかった.
このため,長い文章などを受け取るときに,途中でとぎれるという現象がおきていた.

これを解決したい.

そこで,情報受信側に SocketSever の TCPServer を使うことにした.
このとき,SocketServer.StreamRequestHandler を継承した MyTCPHandler クラスを実装し,TCPサーバーを作成するときに MyTCPHandler をクラスを引き渡す.

この MyTCPHandler の中で socket.recv() の代わりを果たすのが,self.rfile.readline().strip() という部分だ.
self.rfile は,Handler が作成したファイルのようなオブジェクトである.readline() 関数はソケットから流れ込んでくる文字列の中に '\n' を見つけるまで読み続けることができる.

Sender は前回と同じだが,長い文字列を作成するようになっている.


=== Sender === === Receiver ===
from socket import *
from time import sleep
import sys
import os

HOST = ''
PORT = 5008
PORT2 = 5009
BROAD_ADDR = "192.168.50.255"

KEYWORD="Where are you?"

# UDP connection
print "#Connect with UDP"
s =socket(AF_INET, SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, \
SO_BROADCAST, 1)
s.bind((HOST, PORT))

count = 0
pid = os.fork()

if pid == 0:
while count < 30:
print "Looking for a receiver"
msg = KEYWORD
s.sendto(msg, (BROAD_ADDR, PORT))

sleep(2)
count += 1

else:
while count < 60:
msg, addr = s.recvfrom(8192)
if msg.find("I'm") + 1:
print "Found a receiver:", msg
s.sendto(".", (BROAD_ADDR, PORT))
os.kill(pid, 8)
break

count += 1

s.close()

# TCP connection
print "#Connect with TCP to ", addr[0]
s = socket(AF_INET, SOCK_STREAM)
s.connect((addr[0], PORT2))

num=range(10000)
data = \
"<xml>example XML text %s</xml>" \
% str(num)
print "Send:", data
s.send(data)

s.close()
 
import SocketServer
from socket import *
from time import sleep
import sys

HOST = ''
PORT = 5008
PORT2 = 5009
MYADDR = gethostbyname(gethostname())
BROAD_ADDR = "192.168.50.255"

KEYWORD="Where are you?"

# UDP connection
print "#Connect with UDP"
s =socket(AF_INET,SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
s.bind((HOST, PORT))

count = 0
while count < 60:
print "Waiting access from senders..."

msg, address = s.recvfrom(8192)
if msg == ".":
break

if msg == KEYWORD:
print "Recieve: message. Reply to", \
address[0]
print "Reply"
s.sendto("I'm "+ MYADDR, \
(BROAD_ADDR, PORT))
break

sleep(1)
count += 1

s.close()
if count == 60:
sys.exit()

# TCP connection
class MyTCPHandler\
(SocketServer.StreamRequestHandler):

def handle(self):
self.data = self.rfile.readline().strip()
print "Received:", self.data

print "#Connect with TCPServer"

print "Create the server"
server = \
SocketServer.TCPServer((HOST, PORT2), \
MyTCPHandler)

server.handle_request()



TCPServer を使って文字列を送信するには,socket の send() の代わりに,同じくファイルのような Handler のオブジェクト self.wfile を使って self.wfile.write(data) とすることができる.

また TCPServer をアクティブにするために例では sever.handle_request() を実行しているが,sever.server_forever() という関数で,待機し続ける状態にすることもできる.
server.server_forever() を停止するには,server.server_shutdown() を使う.

上記 Sender と Receiver をそれぞれ同一ネットワーク上に存在する1台のマシン(計2台)で実行してみる.
実行結果は以下のようになる.

=== Sender === === Receiver ===
17:16.montepulciano[11] python sender.py
#Connect with UDP
Looking for a receiver
Found a receiver: I'm 192.168.50.11

#Connect with TCP to 192.168.50.18
Send: <xml>example XML text[0, 1, 2,
3, 4, 5, 6, 7, .... 9998, 9999]</xml>

 
17:16.barbaresco[43] python receiver.py
#Connect with UDP
Waiting access from senders...
Recieve message. Reply to 192.168.50.18

#Connect with TCPServer
Create the server
Received: <xml>example XML text [0, 1, 2,
3, 4, 5, 6, 7, .... 9998, 9999]</xml>


受信側の結果をみると,送られてきたのは長い文字列だが,最後まで受信できていることがわかる.



やじるし プログラム間通信関連メモの目次