Apache Thrift クライアントとサーバー間の通信にunix socketを使用する
Thriftを使用し、PythonとNode.jsそれぞれでバイナリデータを送受信するプログラムを作成しました。Apache Thrift Pythonでバイナリデータ(画像)の送受信
Apache Thrift Node.jsでバイナリデータ(画像)の送受信
クライアントとサーバー間の通信にはポート番号を指定してソケットを使用しましたが、
この部分をユニックスソケットに変更してみます。
Python
TSocket.pyのソースを見てみると
https://github.com/apache/thrift/blob/master/lib/py/src/transport/TSocket.py
host、portではなく、unix_socketで指定すれば良いようです。
ソケットは書き込み権限があるパスならどこでも良いのですが、
今回は「/tmp/thrift.sock」としました。
ソースを修正してみます。
・client.py
- # Thriftコンパイラーで出力したテンプレートをパスに追加
- import sys
- sys.path.append('gen-py')
- # テンプレートのファイル名に使用した「sample」にある「Transfer」サービスをimport
- from sample import Transfer
- from thrift import Thrift
- from thrift.transport import TSocket
- from thrift.transport import TTransport
- from thrift.protocol import TBinaryProtocol
- def main():
- # データのやり取りはソケット通信を使用
- # Make socket
- # transport = TSocket.TSocket('localhost', 9090)
- # unix socket使用
- transport = TSocket.TSocket(unix_socket='/tmp/thrift.sock')
- # Buffering is critical. Raw sockets are very slow
- transport = TTransport.TBufferedTransport(transport)
- # プロトコルの指定
- protocol = TBinaryProtocol.TBinaryProtocol(transport)
- # Transferサービスを使用するクライアントを生成
- client = Transfer.Client(protocol)
- # コネクションオープン
- transport.open()
- # 送信するファイル読み込み
- body = open('lena.png', 'rb').read()
- # Transferサービスのsendを実行しファイル送信
- result = client.send('send.png', body)
- print(result)
- # コネクションクローズ
- transport.close()
- if __name__ == '__main__':
- main()
サーバー側もunix_socketを使用するよう変更。
・server.py
- # Thriftコンパイラーで出力したテンプレートをパスに追加
- import sys
- sys.path.append('gen-py')
- # テンプレートのファイル名に使用した「sample」にある「Transfer」サービスをimport
- from sample import Transfer
- from thrift.transport import TSocket
- from thrift.transport import TTransport
- from thrift.protocol import TBinaryProtocol
- from thrift.server import TServer
- class TransferHandler:
- def __init__(self):
- self.log = {}
- def send(self, name, body):
- print(name)
- print(len(body))
- # 受信したファイル名で内容を保存
- open(name, 'wb').write(body)
- return 'ok'
- if __name__ == '__main__':
- handler = TransferHandler()
- processor = Transfer.Processor(handler)
- #transport = TSocket.TServerSocket(host='127.0.0.1', port=9090)
- # unix socket使用
- transport = TSocket.TServerSocket(unix_socket='/tmp/thrift.sock')
- tfactory = TTransport.TBufferedTransportFactory()
- pfactory = TBinaryProtocol.TBinaryProtocolFactory()
- server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)
- # You could do one of these for a multithreaded server
- # server = TServer.TThreadedServer(
- # processor, transport, tfactory, pfactory)
- # server = TServer.TThreadPoolServer(
- # processor, transport, tfactory, pfactory)
- print('Starting the server...')
- server.serve()
- print('done.')
サーバー側を起動。
$ python3 server.py
Starting the server...
/tmp/thrift.sockが生成されました。
クライアント側を実行。
$ python3 client.py
ok
TCPソケットと使用したときと同様、画像ファイルの転送が確認できました。
Node.js
Node.jsでもunix socketを使用するよう修正してみます。
connection.jsのソースを見てみると
https://github.com/apache/thrift/blob/master/lib/nodejs/lib/thrift/connection.js
createUDSConnectionを使用すれば良いようです。
ソースを修正します。
・client.js
- const fs = require('fs').promises;
- // コンパイラで出力したファイルを読み込み
- const Transfer = require('./gen-nodejs/Transfer');
- const thrift = require('thrift');
- const transport = thrift.TBufferedTransport;
- const protocol = thrift.TBinaryProtocol;
- // unixソケットを使用するよう変更
- //const connection = thrift.createConnection('localhost', 9090, {
- const connection = thrift.createUDSConnection('/tmp/thrift.sock', {
- transport : transport,
- protocol : protocol
- });
- connection.on('error', function(err) {
- console.log(err);
- });
- // データ送信用のクライアント生成
- const client = thrift.createClient(Transfer, connection);
- async function main() {
- // 送信データ読み込み
- const body = await fs.readFile('lena.png');
- client.send('send.png', body, function(err, response) {
- if (err) {
- console.log(err);
- } else {
- console.log(response);
- }
- connection.end();
- });
- }
- main();
サーバー側もソースを修正。
・server.js
- const fs = require('fs').promises;
- // コンパイラで出力したファイルを読み込み
- const Transfer = require('./gen-nodejs/Transfer');
- const thrift = require('thrift');
- const server = thrift.createServer(Transfer, {
- // 送信されたファイルを受信
- send: async function(name, body, result) {
- console.log(name);
- await fs.writeFile(name, body);
- result(null, 'ok');
- }
- });
- // unixソケットを使用するよう変更
- //server.listen(9090);
- server.listen('/tmp/thrift.sock');
実行前、/tmp/thrift.sockが残っているとサーバー起動時にエラーとなります。
Python版を実行した後はファイルが残っていたので一旦削除。
$ rm -f /tmp/thrift.sock
サーバー側を起動。
$ node server.js
クライアント側を実行してファイルを送信。
$ node client.js
ok
画像ファイルの転送が確認できました。