10080分でpythonからip messeneger
TRANSCRIPT
1
10080分でPythonから
IP Messenger
山田 聡@denzowill#stapy 2016/01/08
2
WHO ARE YOU?
DBエンジニアですノンプログラマPostgreSQLOracle
3
IP Messeneger
http://ipmsg.org/
4
IP Messenger
●1996年くらいからある?●LAN内でメッセージを投げ合うツール●国産●インフラ系の会社では結構みかける?
5
あらすじ:なんかタスク終わったら自動で担当者にIPMSGで通知して欲しいって言われてやってみたら、送信エラーがでなくて苦しんだので、結局自分で実装することになった話
6
7
だいたい2種類あった
●プロトコルをPurePythonで実装● ipmsg.exeをsubprocessで叩く
8
だいたい2種類あった
●プロトコルをPurePythonで実装● ipmsg.exeをsubprocessで叩く
試したが送信先がいなくてもエラーにならない
9
だいたい2種類あった
●プロトコルをPurePythonで実装● ipmsg.exeをsubprocessで叩く
こっち
10
https://github.com/shaung/ipmsg/
11
ipmsg(Pythonパッケージ)
●pipで入る!●試したら送れた!
12
ipmsg(Pythonパッケージ)
●pipで入る!●試したら送れた!● importしてから使うときのDocない…●そーすむずかしい...●結局送信エラーにならない...
13
そうだ自分で、つくろう
14
そうだ自分で、つくろう→1週間以上経過中
15
そうだ自分で、つくろう→1週間以上経過中7 * 24 * 60 = 10080
16
IP Messenegerのプロトコル
●プロトコル● http://ipmsg.org/protocol.txt
●参考になったサイト● http://smart-pda.net/isourou/ipmsg/doc/ipmsg_protocol.html● http://libipmsg.osdn.jp/specification.html#format
国産プロトコルで日本語Docだし比較的シンプル
17
IP Messenegerのメッセージ以下6要素を:で連結して1行にした文字列で表現
● プロトコルバージョン● 1固定
● パケット番号● インクリメント
● 自分の名前● ホスト名● コマンド
● メッセージの属性(32bit)
● メッセージ● 本文とかその他パケットの追加情報
18
1:100:denzow:MyHost:8405280:こんにちは
19
#!/usr/bin/env python# coding:utf-8
import socket
host = 'xxx.xxx.xxx.xxx' # 嫌いな人のIPアドレスport = 2524serversock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 嫌いなあの人に100通送るfor i in range(1,100): send_msg = "1:%s:denzow:MyHost:8405280:こんにちは" % i print 'Send message...[%s]' % send_msg serversock.sendto(send_msg, (host, port))
投げるだけなら簡単
20
$ ./send.py
嫌いな上司にめがけて
21
$ ./send.py
嫌いな上司にめがけて
22
Ψ(`▽´)Ψ
23
でも、上司がオフラインだったら?
24
でも、上司がオフラインだったら?
$ ./send.py$echo $?0
25
でも、上司がオフラインだったら?
$ ./send.py$echo $?0
失敗してても正常終了
26
(´・ω・`)
27
Why?
●そもそもUDP通信●受信完了のメッセージを相手が戻す規定になっていた
28
’・ω・
こんにちは with :IPMSG_SENDMSGIPMSG_SENDCHECKOPT
・_・`
とんでけー
29
’・ω・
こんにちは with :IPMSG_SENDMSGIPMSG_SENDCHECKOPT
・_・`
こんにちは with :IPMSG_SENDMSGIPMSG_SENDCHECKOPT
You got a mail(届いたかしら)
30
’・ω・
こんにちは with :IPMSG_SENDMSGIPMSG_SENDCHECKOPT
・_・`
こんにちは with :IPMSG_SENDMSGIPMSG_SENDCHECKOPT
IPMSG_RECVMSG
とりあえず応答おくるでー
(届いたかしら)
31
’・ω・
こんにちは with :IPMSG_SENDMSGIPMSG_SENDCHECKOPT
・_・`
こんにちは with :IPMSG_SENDMSGIPMSG_SENDCHECKOPT
IPMSG_RECVMSGIPMSG_RECVMSG
届いてた!
32
So..
●送りたいだけなのにリスニング必須●リスニングしつつ送信なのでスレッド?●送信済メッセージも管理必須
33
So..
●送りたいだけなのにリスニング必須●リスニングしつつ送信なのでスレッド?●送信済メッセージも管理必須●受け取ったメッセージのハンドラ必要● IPわからない場合は名前でおくりたい● import して普通に使えるようにしたい●などなど
34
#!/usr/bin/env python# coding:utf-8
import socket
host = 'xxx.xxx.xxx.xxx' # 嫌いな人のIPアドレスport = 2524serversock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 嫌いなあの人に100通送るfor i in range(1,100): send_msg = "1:%s:denzow:MyHost:8405280:こんにちは" % i print 'Send message...[%s]' % send_msg serversock.sendto(send_msg, (host, port))
投げるだけなら簡単
35
while not self.stop_event.is_set(): r, w, e = select.select([self.sock], [self.sock], [], 0) time.sleep(0.1) # print((r, w, e)) # recive message for sk in r: data, (ip, port) = sk.recvfrom(0x80000) # parse message ip_msg = IpmsgMessageParser(ip, port, com.to_unicode(data)) # action for command self.dispatch_action(ip_msg)
# send message if w and self.send_que: # send message loop until que empty. while self.send_que: # FIFO send_msg = self.send_que.popleft() logger.debug("To[%s:%s]" % (send_msg.addr, send_msg.port)) [logger.debug("\t"+x) for x in send_msg.check_flag()] logger.debug(send_msg.get_full_message()) self.sock.sendto(send_msg.get_full_message(), (send_msg.addr, send_msg.port))
if send_msg.is_sendmsg(): # for check sendmsg success # if long time in the sended que, the message must be failed. send_msg.born_time = datetime.datetime.now() self.sended_que.append(send_msg)
self._cleanup_ques()
投げるだけなら簡単だったのに
サーバ処理のメインループだけで
これ
36
while not self.stop_event.is_set(): r, w, e = select.select([self.sock], [self.sock], [], 0) time.sleep(0.1) # print((r, w, e)) # recive message for sk in r: data, (ip, port) = sk.recvfrom(0x80000) # parse message ip_msg = IpmsgMessageParser(ip, port, com.to_unicode(data)) # action for command self.dispatch_action(ip_msg)
# send message if w and self.send_que: # send message loop until que empty. while self.send_que: # FIFO send_msg = self.send_que.popleft() logger.debug("To[%s:%s]" % (send_msg.addr, send_msg.port)) [logger.debug("\t"+x) for x in send_msg.check_flag()] logger.debug(send_msg.get_full_message()) self.sock.sendto(send_msg.get_full_message(), (send_msg.addr, send_msg.port))
if send_msg.is_sendmsg(): # for check sendmsg success # if long time in the sended que, the message must be failed. send_msg.born_time = datetime.datetime.now() self.sended_que.append(send_msg)
self._cleanup_ques()
投げるだけなら簡単だったのに
ソケットをselectでwatchして
37
while not self.stop_event.is_set(): r, w, e = select.select([self.sock], [self.sock], [], 0) time.sleep(0.1) # print((r, w, e)) # recive message for sk in r: data, (ip, port) = sk.recvfrom(0x80000) # parse message ip_msg = IpmsgMessageParser(ip, port, com.to_unicode(data)) # action for command self.dispatch_action(ip_msg)
# send message if w and self.send_que: # send message loop until que empty. while self.send_que: # FIFO send_msg = self.send_que.popleft() logger.debug("To[%s:%s]" % (send_msg.addr, send_msg.port)) [logger.debug("\t"+x) for x in send_msg.check_flag()] logger.debug(send_msg.get_full_message()) self.sock.sendto(send_msg.get_full_message(), (send_msg.addr, send_msg.port))
if send_msg.is_sendmsg(): # for check sendmsg success # if long time in the sended que, the message must be failed. send_msg.born_time = datetime.datetime.now() self.sended_que.append(send_msg)
self._cleanup_ques()
投げるだけなら簡単だったのに
パケットがきてたらパケットをメッセージにして
アクション
38
while not self.stop_event.is_set(): r, w, e = select.select([self.sock], [self.sock], [], 0) time.sleep(0.1) # print((r, w, e)) # recive message for sk in r: data, (ip, port) = sk.recvfrom(0x80000) # parse message ip_msg = IpmsgMessageParser(ip, port, com.to_unicode(data)) # action for command self.dispatch_action(ip_msg)
# send message if w and self.send_que: # send message loop until que empty. while self.send_que: # FIFO send_msg = self.send_que.popleft() logger.debug("To[%s:%s]" % (send_msg.addr, send_msg.port)) [logger.debug("\t"+x) for x in send_msg.check_flag()] logger.debug(send_msg.get_full_message()) self.sock.sendto(send_msg.get_full_message(), (send_msg.addr, send_msg.port))
if send_msg.is_sendmsg(): # for check sendmsg success # if long time in the sended que, the message must be failed. send_msg.born_time = datetime.datetime.now() self.sended_que.append(send_msg)
self._cleanup_ques()
投げるだけなら簡単だったのに
送信キューにメッセージがあればFIFOで処理
39
while not self.stop_event.is_set(): r, w, e = select.select([self.sock], [self.sock], [], 0) time.sleep(0.1) # print((r, w, e)) # recive message for sk in r: data, (ip, port) = sk.recvfrom(0x80000) # parse message ip_msg = IpmsgMessageParser(ip, port, com.to_unicode(data)) # action for command self.dispatch_action(ip_msg)
# send message if w and self.send_que: # send message loop until que empty. while self.send_que: # FIFO send_msg = self.send_que.popleft() logger.debug("To[%s:%s]" % (send_msg.addr, send_msg.port)) [logger.debug("\t"+x) for x in send_msg.check_flag()] logger.debug(send_msg.get_full_message()) self.sock.sendto(send_msg.get_full_message(), (send_msg.addr, send_msg.port))
if send_msg.is_sendmsg(): # for check sendmsg success # if long time in the sended que, the message must be failed. send_msg.born_time = datetime.datetime.now() self.sended_que.append(send_msg)
self._cleanup_ques()
投げるだけなら簡単だったのに
送信ミスとかでキューに長くのこった
メッセージ等のクリーンアップ
40
よかったら
●GitHubにあげるだけあがってます● https://github.com/denzow/ipymessenger
●Docとコメントは週明けに日本語に変更● IPMSGは海外需要ない気がしてきたので…
●送信は実装済●受信は週明けに実装(希望)
41
つまり:なんかタスク終わったら自動で担当者にIPMSGで通知して欲しいって言われてやってみたら、送信エラーがでなくて苦しんだので、結局自分で実装することになった話
42
つまり:なんかタスク終わったら自動で担当者にIPMSGで通知して欲しいって言われてやってみたら、送信エラーがでなくて苦しんだので、結局自分で実装することになった話
人の、10080分が短縮できれば幸いです
43
ありがとうございました。