P2Pメッセンジャーの作成







インターネットメッセンジャーの未来について議論し、 「なぜあなたのお気に入りのメッセンジャーが死ぬべきか」という記事を読んだ背景を背景に、サードパーティのサーバーに関係なく通信用のP2Pアプリケーションを作成した経験を共有することにしました。 より正確には、クライアントからサーバーに1つのメッセージを転送するだけの空白であり、機能のさらなる拡張はあなたの想像力にのみ依存します。



この出版物では、世界中のどこからでもP2P通信用の3つの簡単なアプリケーション、クライアント、サーバー、シグナルサーバーを作成します。



必要なもの:

-白い静的IPアドレスを持つ1つのサーバー。

-接続タイプがFull Cone NATのNAT用の2台のコンピューター(または2台の仮想マシンを持つ1台のコンピューター)。

-STUNサーバー。



フルコーンNATは、「内部アドレス:内部ポート」と「パブリックアドレス:パブリックポート」のペア間に明確な変換があるネットワークアドレス変換の一種です。



WikiでSTUNサーバーについて読むことができるものは次のとおりです。

「UDPパケットを使用してIPネットワーク経由で音声、画像、またはテキストを送信するプロトコルがあります。 残念ながら、通信する両方のパーティがNATの背後にある場合、通常の方法では接続を確立できません。 これは、STUNが役立つ場所です。 これにより、アドレス変換サーバー(またはこれらのサーバーのいくつか)の背後にあるクライアントは、外部IPアドレス、特定の内部ポート番号に関連付けられた外部ネットワークでのアドレスとポートの変換方法を決定できます。



問題を解決するときに、次のPythonモジュールが使用されました:socket、twisted、stun、sqlite3、os、sys。



サーバーとクライアント間、およびサーバー、クライアント、シグナルサーバー間のデータ交換には、UDPプロトコルが使用されます。



一般的に、機能メカニズムは次のようになります。



サーバー<-> STUNサーバー

クライアント<-> STUNサーバー



サーバー<->シグナルサーバー

クライアント<->シグナルサーバー



クライアント->サーバー



1.接続タイプがFull Cone NATのNATの背後にあるクライアントは、STUNサーバーにメッセージを送信し、外部IPの形式で応答を受信し、PORTを開きます。



2.接続タイプがFull Cone NATのNATの背後にあるサーバーは、STUNサーバーにメッセージを送信し、外部IPの形式で応答を受信し、PORTを開きます。



同時に、クライアントとサーバーは、Signal Serverの外部(白い)IPとPORTを認識しています。



3.サーバーは外部IPとPORTでデータをSignal Serverに送信し、Signal Serverはそれらを保存します。



4.クライアントは、外部IPおよびPORTのデータと、外部IP PORTが予期する目的のサーバーのid_destinationのデータをSignal Serverに送信します。



Signal Serverはそれらを保存し、id_destinationを使用してデータベースを検索し、応答として、文字列として見つかった情報を返します: 'id_host、name_host、ip_host、port_host';



5.クライアントは、見つかった情報を受け入れ、区切り文字で区切り、(ip_host、port_host)を使用して、サーバーにメッセージを送信します。



アプリケーションは、Debian 7.7でテストされたPythonバージョン2.7で書かれています。



内容を含むserver.pyファイルを作成します。

server.py
# -*- coding: utf-8 -*- #SERVER from socket import * import sys import stun def sigserver_exch(): #  <->   #  <-  #  -         IP       IP  PORT.    . # IP  PORT  : v_sig_host = 'XX.XX.XX.XX' v_sig_port = XXXX #id  ,   , id   v_id_client = 'id_server_1002' v_name_client = 'name_server_2' v_id_server = 'none' #IP  PORT   v_ip_localhost = 'XX.XX.XX.XX' v_port_localhost = XXXX udp_socket = '' try: #   IP  PORT    STUN nat_type, external_ip, external_port = stun.get_ip_info() #   IP  PORT      host_sigserver = v_sig_host port_sigserver = v_sig_port addr_sigserv = (host_sigserver,port_sigserver) #       : # id +  +   IP  PORT, # id_dest -  'none' #  id      +  data_out = v_id_client + ',' + v_name_client + ',' + external_ip + ',' + str(external_port) + ',' + v_id_server #   : #    (AF_INET), #      udp_socket = socket(AF_INET, SOCK_DGRAM) #    IP   PORT    host = v_ip_localhost port = v_port_localhost addr = (host,port) #    IP  PORT udp_socket.bind(addr) print('socket binding') #     udp_socket.sendto(data_out,addr_sigserv) while True: #    - 'sigserv' (   ), #     # -   'Message from CLIENT!' data_in = udp_socket.recvfrom(1024) if data_in[0] == 'sigserv': print('signal server data: ', data_in) else: print('Message from CLIENT!') #  udp_socket.close() except: print('exit!') sys.exit(1) finally: if udp_socket <> '' udp_socket.close() sigserver_exch()
      
      







セクションの適切なフィールドに入力します:「外部IPとシグナルサーバーのポート」および「このクライアントのIPとポート」。



内容を含むclient.pyファイルを作成します。

client.py
 # -*- coding: utf-8 -*- # CLIENT from socket import * import sys import stun def sigserver_exch(): #  <->   #  ->  #  -        IP #     IP  PORT   NAT    . # IP  PORT  : v_sig_host = 'XX.XX.XX.XX' v_sig_port = XXXX #id  ,   , id   v_id_client = 'id_client_1001' v_name_client = 'name_client_1' v_id_server = 'id_server_1002' #IP  PORT   v_ip_localhost = 'XX.XX.XX.XX' v_port_localhost = XXXX udp_socket = '' try: #   IP  PORT    STUN nat_type, external_ip, external_port = stun.get_ip_info() #   IP  PORT      host_sigserver = v_sig_host port_sigserver = v_sig_port addr_sigserv = (host_sigserver,port_sigserver) #       : # id +  +   IP  PORT, # id_dest - id      . #  id      +  data_out = v_id_client + ',' + v_name_client + ',' + external_ip + ',' + str(external_port) + ',' + v_id_server #   : #    (AF_INET), #      udp_socket = socket(AF_INET, SOCK_DGRAM) #    IP   PORT    host = v_ip_localhost port = v_port_localhost addr = (host,port) #    IP  PORT udp_socket.bind(addr) #     udp_socket.sendto(data_out, addr_sigserv) while True: #    - 'sigserv' (   ), #        #'Hello, SERVER!'       . data_in = udp_socket.recvfrom(1024) data_0 = data_in[0] data_p = data_0.split(",") if data_p[0] == 'sigserv': print('signal server data: ', data_p) udp_socket.sendto('Hello, SERVER!',(data_p[3],int(data_p[4]))) else: print("No, it is not Rio de Janeiro!") udp_socket.close() except: print ('Exit!') sys.exit(1) finally: if udp_socket <> '' udp_socket.close() sigserver_exch()
      
      







セクションの適切なフィールドに入力します:「外部IPとシグナルサーバーのポート」および「このクライアントのIPとポート」。



内容を含むsignal_server.pyファイルを作成します。

signal_server.py
 # -*- coding: utf-8 -*- # SIGNAL SERVER #Twisted -  (event)  #   – event handler #        event handler #     reactor   twisted.internet from twisted.internet import reactor from twisted.internet.protocol import DatagramProtocol import sys, os import sqlite3 class Query_processing_server(DatagramProtocol): #   <->  #  ->  #  #   <->  #   -       #     IP  PORT # (  -   +   ) #   IP  PORT   . def datagramReceived(self, data, addr_out): conn = '' try: #     (,) [id_host,name_host,external_ip,external_port,id_dest] #id_dest -  id  data = data.split(",") #       sqlite3,         : path_to_db = raw_input('Enter name db. For example: "/home/user/new_db.db": ') path_to_db = os.path.join(path_to_db) #    conn = sqlite3.connect(path_to_db) #    conn.text_factory = str #   c = conn.cursor() #     c.execute('''CREATE TABLE IF NOT EXISTS compliance_table ("id_host" text UNIQUE, "name_host" text, "ip_host" text, \ "port_host" text)''') #  ,     #  ip, port    c.execute('INSERT OR IGNORE INTO compliance_table VALUES (?, ?, ?, ?);', data[0:len(data)-1]) #  conn.commit() c.execute('SELECT * FROM compliance_table') #      id c.execute('''SELECT id_host, name_host, ip_host, port_host from compliance_table WHERE id_host=?''', (data[len(data)-1],)) cf = c.fetchone() if cf == None: print ('Server_id not found!') else: #transport.write -    : id_host, name_host, ip_host, port_host   sigserver lst = 'sigserv' + ',' + cf[0] + ',' + cf[1] + ',' + cf[2] + ',' + cf[3] self.transport.write(str(lst), addr_out) #  conn.close() except: print ('Exit!') sys.exit(1) finally: if conn <> '' conn.close() reactor.listenUDP(9102, Query_processing_server()) print('reactor run!') reactor.run()
      
      









できた!



アプリケーションの起動順序は次のとおりです。

-signal_server.py

-server.py

-client.py



All Articles