10080分でPythonからIP Messeneger

854 views
978 views

Published on

PythonでIP Messengerを使った話です。
http://startpython.connpass.com/event/24092/
のライトニングトークです

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
854
On SlideShare
0
From Embeds
0
Number of Embeds
362
Actions
Shares
0
Downloads
7
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

10080分でPythonからIP Messeneger

  1. 1. 1 10080分で Pythonから IP Messenger 山田 聡@denzowill #stapy 2016/01/08
  2. 2. 2 WHO ARE YOU? DBエンジニアです ノンプログラマ PostgreSQL Oracle
  3. 3. 3 IP Messeneger http://ipmsg.org/
  4. 4. 4 IP Messenger ● 1996年くらいからある? ● LAN内でメッセージを投げ合うツール ● 国産 ● インフラ系の会社では結構みかける?
  5. 5. 5 あらすじ: なんかタスク終わったら自動で 担当者にIPMSGで通知して欲しいって 言われてやってみたら、送信エラーが でなくて苦しんだので、結局自分で実 装することになった話
  6. 6. 6
  7. 7. 7 だいたい2種類あった ● プロトコルをPurePythonで実装 ● ipmsg.exeをsubprocessで叩く
  8. 8. 8 だいたい2種類あった ● プロトコルをPurePythonで実装 ● ipmsg.exeをsubprocessで叩く 試したが 送信先がいなくても エラーにならない
  9. 9. 9 だいたい2種類あった ● プロトコルをPurePythonで実装 ● ipmsg.exeをsubprocessで叩く こっち
  10. 10. 10 https://github.com/shaung/ipmsg/
  11. 11. 11 ipmsg(Pythonパッケージ) ● pipで入る! ● 試したら送れた!
  12. 12. 12 ipmsg(Pythonパッケージ) ● pipで入る! ● 試したら送れた! ● importしてから使うときのDocない… ● そーすむずかしい... ● 結局送信エラーにならない...
  13. 13. 13 そうだ自分で、つくろう
  14. 14. 14 そうだ自分で、つくろう →1週間以上経過中
  15. 15. 15 そうだ自分で、つくろう →1週間以上経過中 7 * 24 * 60 = 10080
  16. 16. 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. 17. 17 IP Messenegerのメッセージ 以下6要素を:で連結して1行にした文字列で表現 ● プロトコルバージョン ● 1固定 ● パケット番号 ● インクリメント ● 自分の名前 ● ホスト名 ● コマンド ● メッセージの属性(32bit) ● メッセージ ● 本文とかその他パケットの追加情報
  18. 18. 18 1:100:denzow:MyHost:8405280:こんにちは
  19. 19. 19 #!/usr/bin/env python # coding:utf-8 import socket host = 'xxx.xxx.xxx.xxx' # 嫌いな人のIPアドレス port = 2524 serversock = 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. 20. 20 $ ./send.py 嫌いな上司にめがけて
  21. 21. 21 $ ./send.py 嫌いな上司にめがけて
  22. 22. 22 Ψ(`▽´)Ψ
  23. 23. 23 でも、上司がオフライン だったら?
  24. 24. 24 でも、上司がオフライン だったら? $ ./send.py $echo $? 0
  25. 25. 25 でも、上司がオフライン だったら? $ ./send.py $echo $? 0 失敗してても正常終了
  26. 26. 26 (´・ω・`)
  27. 27. 27 Why? ● そもそもUDP通信 ● 受信完了のメッセージを相手が戻す 規定になっていた
  28. 28. 28 ’・ω・ こんにちは with : IPMSG_SENDMSG IPMSG_SENDCHECKOPT ・_・` とんでけー
  29. 29. 29 ’・ω・ こんにちは with : IPMSG_SENDMSG IPMSG_SENDCHECKOPT ・_・` こんにちは with : IPMSG_SENDMSG IPMSG_SENDCHECKOPT You got a mail (届いたかしら)
  30. 30. 30 ’・ω・ こんにちは with : IPMSG_SENDMSG IPMSG_SENDCHECKOPT ・_・` こんにちは with : IPMSG_SENDMSG IPMSG_SENDCHECKOPT IPMSG_RECVMSG とりあえず応答 おくるでー (届いたかしら)
  31. 31. 31 ’・ω・ こんにちは with : IPMSG_SENDMSG IPMSG_SENDCHECKOPT ・_・` こんにちは with : IPMSG_SENDMSG IPMSG_SENDCHECKOPT IPMSG_RECVMSGIPMSG_RECVMSG 届いてた!
  32. 32. 32 So.. ● 送りたいだけなのにリスニング必須 ● リスニングしつつ送信なのでスレッド? ● 送信済メッセージも管理必須
  33. 33. 33 So.. ● 送りたいだけなのにリスニング必須 ● リスニングしつつ送信なのでスレッド? ● 送信済メッセージも管理必須 ● 受け取ったメッセージのハンドラ必要 ● IPわからない場合は名前でおくりたい ● import して普通に使えるようにしたい ● などなど
  34. 34. 34 #!/usr/bin/env python # coding:utf-8 import socket host = 'xxx.xxx.xxx.xxx' # 嫌いな人のIPアドレス port = 2524 serversock = 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. 35. 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. 36. 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. 37. 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. 38. 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. 39. 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. 40. 40 よかったら ● GitHubにあげるだけあがってます ● https://github.com/denzow/ipymessenger ● Docとコメントは週明けに日本語に変更 ● IPMSGは海外需要ない気がしてきたので… ● 送信は実装済 ● 受信は週明けに実装(希望)
  41. 41. 41 つまり: なんかタスク終わったら自動で 担当者にIPMSGで通知して欲しいって 言われてやってみたら、送信エラーが でなくて苦しんだので、結局自分で実 装することになった話
  42. 42. 42 つまり: なんかタスク終わったら自動で 担当者にIPMSGで通知して欲しいって 言われてやってみたら、送信エラーが でなくて苦しんだので、結局自分で実 装することになった話 人の、10080分が 短縮できれば幸いです
  43. 43. 43 ありがとうございました。

×