Python を使ってプログラム間通信の仕方を勉強している.

これまでに,socket レベルの関数を用いて,TCP を使った情報の送受信とUDP を使ったブロードキャストの仕方を学んだ.
今回は,これらを組み合わせて以下のような仕様のプログラムを作る.

情報の sender は,receiver がどこにいるかわからない.
なので,sender は,あるメッセージをブロードキャストに投げる.同時にブロードキャストメッセージの受信に備える.
receiver は,ブロードキャストメッセージを待ち受けていて,あるメッセージがどこかから届いたら,同じくブロードキャストに自分の IP アドレスを送る.
sender は receiver からの返信を受け取って,receiver がネットワーク内に居ることとその IP アドレスを確認する.

ここまでで,sender は receiver の IP アドレスを知ることができた.

次に,sender は receiver の IP アドレスに対して TCP コネクションを張ることを試みる.
receiver は TCP コネクションの接続要求待ち状態になっている.
ここでコネクションが成立すれば,sender は情報を送り,receiver は情報を受け取る.

ここでいう情報とは何らかの文字列である.例では XML センテンスを送っている.

上記のような振る舞いを期待して以下のコードを書いた.


=== 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, address = 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 "\n#Connect with TCP"
s = socket(AF_INET, SOCK_STREAM)
s.connect((address[0], PORT2))

data = "example XML text"
print "Send:", data
s.send(data)

s.close()

 
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]
s.sendto("I'm "+ MYADDR, \
(BROAD_ADDR, PORT))
break

sleep(1)
count += 1

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

# TCP connection
print "\n#Connect with TCP"
s = socket(AF_INET, SOCK_STREAM)
s.bind((HOST, PORT2))
s.listen(1)
(conn, addr) = s.accept()

data = conn.recv(1024)

conn.close()

if data:
print "Received: ",data
else:
print "no data"


上記 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
Send: <xml>example XML text</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 TCP
Received: <xml>example XML text</xml>




実はこれにはまだ不具合がある.
送信するメッセージ(例ではXMLセンテンス)が長くなると,センテンスの前の方の一部のみしか受信できないことがある.
これは情報が複数のパケットに断片的に乗っており,そのパケットがばらばらと届いているのに,そのパケットを拾いきれていないからだと Dr. K にアドバイスをもらった.

情報が断片的に乗っている複数のパケットを全て的確に受信するように改良する必要がある.




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