
インターネットメッセンジャーの未来について議論し、 「なぜあなたのお気に入りのメッセンジャーが死ぬべきか」という記事を読んだ背景を背景に、サードパーティのサーバーに関係なく通信用の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