述語インターフェース名 | 概要説明 | 通常(※1) | Windows | Linux/Mac | |
A | server_create/2 , server_create/3 | ソケットサーバーを生成します | ○ | ○ | ○ |
---|---|---|---|---|---|
server_accept/3 | クライアントからの接続要求時に接続を確立します | ○ | ○ | ○ | |
client_connect/3 | ソケット接続の接続要求を行います | ○ | ○ | ○ | |
client_connect_async/3 | ソケット接続の接続要求を非同期で行います | ○ | × | ○ | |
socket_send/2 | ソケットにデータを送信します | ○ | ○ | ○ | |
socket_send_list/2 | ソケットにリストを送信します | ○ | ○ | ○ | |
socket_receive/2 | ソケットからデータを受信します | ○ | ○ | ○ | |
socket_receive_list/2 | ソケットからリストを受信します | ○ | ○ | ○ | |
socket_close/1 | ソケット接続を終了します | ○ | ○ | ○ | |
select_from_sockets/3 | ソケットリストからデータを受信しているソケットを抽出します | ○ | ○ | ○ | |
host2ip/4 | ホスト名をIPアドレスに変換します | ○ | ○ | ○ | |
B | ssl_client_connect/4 | SSLソケット接続の接続要求を行います | ○ | ○ | |
ssl_socket_send/2 | SSLソケットにデータを送信します | ○ | ○ | ||
ssl_socket_receive/2 | SSLソケットからデータを受信します | ○ | ○ | ||
ssl_socket_close/1 | SSLソケット接続を終了します | ○ | ○ | ||
C | ssl_cert_load_cafile/3 | サーバー証明書ファイル(CA)で認証を行いソケット接続を確立します | ○ | ○ | |
ssl_cert_load_file/4 | サーバー証明書ファイル(CA)と秘密鍵ファイル(Private Key)で認証を行いソケット接続を確立します | ○ | ○ | ||
ssl_cert_load_data/4 | サーバー証明書データ(CA)と秘密鍵データ(Private Key)で認証を行いソケット接続を確立します | ○ | ○ | ||
ssl_cert_send/2 | 認証されたソケットにデータを送信します | ○ | ○ | ||
ssl_cert_receive/3 | 認証されたソケットからデータを受信します | ○ | ○ | ||
ssl_cert_close/1 | SSLコンテキストを解放します。 | ○ | ○ | ||
D | socket_download/2 | ソケットからデータを受信しファイルへ書き込みます | ○ | ○ | ○ |
socket_ssl_download/2 | SSLソケットからデータを受信しファイルへ書き込みます | ○ | ○ | ||
E | unix_client_connect/2 | UNIXソケットよりソケット接続の接続要求を行います | ○ | × | ○ |
unix_server_create/2 | UNIXソケットよりソケットサーバーを生成します | ○ | × | ○ | |
unix_server_close/2 | UNIXソケットでのソケット接続を終了します | ○ | × | ○ | |
F | check_socket_receivable/1 | ソケットに読み込みデータがあるかを確認します | ○ | ○ | ○ |
check_socket_sendable/1 | ソケットディスクリプタの接続確立状況を確認します | ○ | ○ | ○ | |
G | ping/2 | ネットワーク疎通を確認します | ○ | × | ○ |
ping_async/2 | ネットワーク疎通確認をソケットを通して行います | ○ | × | ○ | |
H | ws_set_log_level/1 | libwebsocketsのログ出力レベルを指定する | ○ | × | ○ |
ws_set_client_certificate_file_path/1 | クライアント側certificate fileのパスを指定する | ○ | × | ○ | |
ws_set_client_private_key_file_path/1 | クライアント側private key fileのパスを指定する | ○ | × | ○ | |
ws_create_context/3 | クライアント側のCONTEXTを生成する | ○ | × | ○ | |
ws_delete_context/1 | CONTEXTを削除する | ○ | × | ○ | |
ws_connect/10 | サーバに接続して、生成されたSESSIONを返す | ○ | × | ○ | |
ws_close/1 | 接続SESSIONを閉じる | ○ | × | ○ | |
ws_is_close/2 | 接続SESSIONを閉じる | ○ | × | ○ | |
ws_sub_protocol/2 | 指定されたSESSIONのsub-protocolを返す | ○ | × | ○ | |
ws_read_text/3 | テキストデータを読み込む | ○ | × | ○ | |
ws_write_text/2 | テキストデータを送信する | ○ | × | ○ | |
ws_write_atom_list/2 | アトム並びリストのテキストデータを送信する | ○ | × | ○ | |
ws_read_list/3 | バイナリデータを読み込む | ○ | × | ○ | |
ws_write_list_binary/2 | バイナリデータを送信する | ○ | × | ○ | |
ws_write_pong/1 | PONGを送信する | ○ | × | ○ | |
ws_version/1 | バージョン情報を取得する | ○ | × | ○ |
Aグループ | 通常ソケット関連述語 | ||||
---|---|---|---|---|---|
Bグループ | SSLソケット関連述語 | ||||
Cグループ | 証明書認証関連述語 | ||||
Dグループ | ファイルダウンロード関連述語 | ||||
Eグループ | UNIXソケット関連述語 | ||||
Fグループ | 読込みデータ及び接続の確認関連述語 | ||||
Gグループ | 疎通確認関連述語 | ||||
Hグループ | WEBソケット関連述語 |
[Windows]
${AZProlog} = インストールディレクトリ
${AZProlog}¥lib¥ext¥socket.dll
${AZProlog}¥lib¥ext¥socket_ssl.dll
[Linux]
${AZProlog} = /usr/local またはインストールディレクトリ
${AZProlog}lib/azprolog/ext/socket.so
${AZProlog}lib/azprolog/ext/socket_ssl.so
${AZProlog}lib/azprolog/ext/websock.so
[Mac]
${AZProlog} = /Applications/azprolog.app/Contents/az_home/ またはインストールディレクトリ
${AZProlog}lib/azprolog/ext/socket.dylib
${AZProlog}lib/azprolog/ext/socket_ssl.dylib
${AZProlog}lib/azprolog/ext/websock.dylib
OpenSSLをインストールする場合は、OpenSSLサイトよりインストーラーをダウンロードし起動してインストールを行います。
Cryptoをインストールする場合は、Cryptoサイトよりライブラリまたはコンパイルソース一式をダウンロードします。
なお、コンパイルソース一式をダウンロードする場合は、コンパイルを実施しライブラリの生成を行います。
※ライブラリ生成後は、Windowsシステム・ディレクトリ(WindowsSystem32)にコピーします。
【OpenSSLのダウンロード】
http://slproweb.com/products/Win32OpenSSL.html
Win32 OpenSSL v1.0.2
または
Win64 OpenSSL v1.0.2
【Cryptoのダウンロード】
http://www.cryptopp.com/#download
バイナリのダウンロードは、サイトの中ごろにあるリンクをクリックして行います。
「FIPS 140-2 Conformance」
・Crypto++ Library 5.3.0 (32-bit and 64-bit Windows DLL, calling application must be compiled with MSVC 2005) [download package] [download PGP signature] [certificate #819]
→[download package]のリンクをクリックします。(2015.03.09現在でバージョンは5.3.0が最新です)
インストール後は、以下に示すライブラリファイルが Windowsシステム・ディレクトリ(WindowsSystem32)に存在するか確認します。もし、1つでもライブラリファイルが存在しない場合は、ライブラリのロード述語で失敗する可能性があります。
- ssleay32.dll
- libeay32.dll
- cryptopp.dll
$ sudo apt-get install openssl $ sudo apt-get install libssl-dev
$ sudo port install openssl
AZ-Prolog を立ち上げ、ソケットライブラリがロードできるか確認します。
$ prolog | ?-dlib_require(socket). yes | ?-
通常ソケット関連の述語を利用する場合は、上記のように必ず dlib_require で socket ライブラリをロードしてください。
$ prologWEBソケット関連の述語を利用する場合は、上記のように必ずdlib_requireで、websockライブラリをロードしてください。
| ?-dlib_require(websock).
yes
| ?-
$ prolog | ?-dlib_require(socket_ssl). yes | ?-SSLソケット関連の述語を利用する場合は、上記のように必ず dlib_require でsocket_ssl ライブラリをロードしてください。
go:-server_create('5000',Acc), repeat, all_acc(1,WatchList), select_from_sockets(20000,[Acc|WatchList],ReceivedList), member(Sock,ReceivedList), rec_do(Acc,Sock,Data), write(Sock=Data),nl, fail. rec_do(A,A,_):- !,server_accept(A,Host,S),assert('$acc$'(S)),fail. rec_do(_,S,D):- socket_receive_list(S,D),length(D,N),N>0,!. rec_do(_,S,_):- socket_close(S),retract('$acc$'(S)),fail. all_acc(N,[A|L]):- clause('$acc$',1,N,'$acc$'(A)),!,NN is N+1,all_acc(NN,L). all_acc(_,[]). ?-go. 4=[97,98,99,100,101,102,103,13,10]
ソケットサーバーのサーバー生成述語を定義し、その後述語を実行しクライアントからの接続待機を行う。
上記の例ではソケットサーバーを5000ポートで生成し、クライアントからの接続を待機する。
その後、クライアントからの接続が確立された場合は、データ受信を行い受信データをリストで表示している。
$ telnet localhost 5000 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. abcdefg
telnetコマンドでソケットサーバー(localhost)に5000ポートで接続し データ(abcdefg) を入力
<クライアント側:同期>
test:- client_connect('127.0.0.1','5000',S), socket_send(S,'TEST'), socket_close(S). ?-test. yes ?-
ソケットサーバーへ接続しデータを送信する述語を定義し、その後述語を実行しソケットサーバーへデータを送信する。
上記の例では、ソケットサーバー(127.0.0.1)に5000ポートで接続しデータを送信している。
get_request(Url):- client_connect('127.0.0.1','80',S), name(CR,[10]), atom_concat('GET ',Url,P1), atom_concat(P1,' HTTP/1.1',P2), atom_concat(P2,CR,P3), atom_concat(P3,'Host: 127.0.0.1',P4), atom_concat(P4,CR,P5), atom_concat(P5,'Connection: Close',P6), atom_concat(P6,CR,P7), atom_concat(P7,CR,Get), socket_send(S,Get), get_all(S,"""",LAns), socket_close(S), name(Ans,LAns), write(Ans). get_all(Sock2,Bef,Ans):- select_from_sockets(20000,[Sock2],[Sock3]), socket_receive_list(Sock3,Out),length(Out,N),N>0,!, append(Bef,Out,NextBef), get_all(Sock3,NextBef,Ans). get_all(Sock2,A,A). ?-get_request('/index_test.html'). HTTP/1.1 200 OK Date: Mon, 02 Dec 2013 09:33:50 GMT Server: Apache/2.2.22 (Ubuntu) Last-Modified: Mon, 02 Dec 2013 09:29:57 GMT ETag: ""161652-2d-4ec89d2c4b7a4"" Accept-Ranges: bytes Content-Length: 45 Vary: Accept-Encoding Connection: close Content-Type: text/html ‹html› ‹body› Test Test Test ‹/body› ‹/html› yes ?-
WEBサーバーからGETリクエストでコンテンツを取得する述語を定義し、その後述語を実行し取得したコンテンツを表示する。
上記の例ではWEBサイト(127.0.0.1)にHttpポート(80)で接続し、GETリクエストで指定のコンテンツを取得し表示している。
get_from_proxy(Url):- client_connect('127.0.0.1','3128',S), name(CR,[10]), atom_concat('GET ',Url,P1), atom_concat(P1,' HTTP/1.1',P2), atom_concat(P2,CR,P3), atom_concat(P3,'Host: 127.0.0.1',P4), atom_concat(P4,CR,P5), atom_concat(P5,'Connection: Close',P6), atom_concat(P6,CR,P7), atom_concat(P7,CR,Get), socket_send(S,Get), get_all(S,"""",LAns), socket_close(S), name(Ans,LAns), write(Ans). get_all(Sock2,Bef,Ans):- select_from_sockets(20000,[Sock2],[Sock3]), socket_receive_list(Sock3,Out),length(Out,N),N>0,!, append(Bef,Out,NextBef), get_all(Sock3,NextBef,Ans). get_all(Sock2,A,A). ?-get_from_proxy('http://www.yahoo.co.jp'). HTTP/1.0 200 OK Date: Mon, 02 Dec 2013 09:11:33 GMT P3P: policyref=""http://privacy.yahoo.co.jp/w3c/p3p.xml"", CP=""CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"" Expires: -1 Pragma: no-cache Cache-Control: private, no-cache, no-store, must-revalidate X-XRDS-Location: http://open.login.yahoo.co.jp/openid20/www.yahoo.co.jp/xrds Vary: Accept-Encoding Content-Type: text/html; charset=utf-8 X-Cache: MISS from localhost X-Cache-Lookup: MISS from localhost:3128 Via: 1.0 localhost (squid/3.1.19) Connection: close ・ <== コンテンツ表示を省略 ・ <== コンテンツ表示を省略 ・ <== コンテンツ表示を省略 ‹/body› ‹/html› yes ?-
Proxyサーバー経由でWEBサーバーからGETリクエストでコンテンツを取得する述語を定義し、その後述語を実行し取得したコンテンツを表示する。
上記の例ではProxyサーバー(127.0.0.1)経由でWebサイト(localhost)にHttpポート(80)で接続し、GETリクエストで指定のコンテンツを取得し表示している。
get_ssl_request(Host):- host2ip(Host,GH,AH,IP), ssl_client_connect(IP,'443','RSA',S), name(C,[10]), D1 = 'GET / HTTP/1.1', atom_concat(D1,C,D2), atom_concat(D2,'Host: ',D3), atom_concat(D3,Host,D4), atom_concat(D4,':443',D5), atom_concat(D5,C,D6), atom_concat(D6,'Connection: Close',D7), atom_concat(D7,C,D8), atom_concat(D8,C,Data), ssl_socket_send(S,Data), get_all(S,"""",LAns), name(Ans,LAns), write(Ans),nl, ssl_socket_close(S). get_all(Sock2,Bef,Ans):- ssl_socket_receive(Sock2,Out),name(Out,OutL),length(OutL,N),N>0,!, append(Bef,OutL,NextBef), get_all(Sock2,NextBef,Ans). get_all(Sock2,A,A). ?-get_ssl_request('www.verisign.co.jp'). HTTP/1.1 200 OK Server: """" Date: Mon, 02 Dec 2013 05:51:28 GMT Content-type: text/html Connection: close ‹!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01 Transitional//EN"" ""http://www.w3.org/TR/html4/loose.dtd""› ‹html lang=""ja""› ‹head› ‹link rel=""canonical"" href=""https://www.verisign.co.jp/""› ・ <== コンテンツ表示を省略 ・ <== コンテンツ表示を省略 ・ <== コンテンツ表示を省略 ‹/body› ‹/html› yes ?-
指定されたホストにSSLで接続し、GETリクエストでコンテンツを取得する述語を定義し、その後述語を実行し取得したコンテンツを表示する。
上記の例ではベリサインのサイト(www.verisign.co.jp)にSSLで接続し、GETリクエストでトップサイトのコンテンツを取得し表示している。
test:- IP='127.0.0.1', CERT_FILE='server.pem', client_connect(IP,'3000',S), ssl_cert_load_cafile(S,CERT_FILE,S2), name(C,[10]), Data1='Get Data Request', atom_concat(Data1,C,Data), ssl_cert_send(S2,Data), get_all(S2,"""",LAns), name(Ans,LAns), write(Ans),nl, socket_close(S), ssl_cert_close(S2). get_all(SN,Bef,Ans):- ssl_cert_receive(SN,Out,Sz),name(Out,OutL),length(OutL,N),N>0,!, append(Bef,OutL,NextBef), get_all(SN,NextBef,Ans). get_all(SN,A,A). ?-test. Welcome !! Test Certificate Data yes ?-
ソケットサーバーに認証接続を行いデータの送受信を行う述語を定義し、その後述語を実行し受信データを表示する。
上記の例ではソケットサーバー(localhost)にクライアント接続し証明書ファイル認証を行い、その後データの送受信を行って受信データを表示している。
test:- client_connect('127.0.0.1','80',S), P1='GET /icon.zip HTTP/1.1', name(C,[10]), atom_concat(P1,C,P2), atom_concat(P2,'Host: 127.0.0.1',P3), atom_concat(P3,C,P4), atom_concat(P4,'Connection: Close',P5), atom_concat(P5,C,P6), atom_concat(P6,C,Get), socket_send(S,Get), socket_download(S, 'icon.zip'), socket_close(S). ?-test. yes ?-
ソケットサーバーにクライアント接続しGETリクエストでファイルをダウンロードする述語を定義し、その後述語を実行しファイルをダウンロードする。
上記の例ではWebサイト(localhost)にHttpポート(80)で接続し、GETリクエストでバイナリファイルをダウンロードしている。
go:-unix_server_create('/tmp/test.sock',Acc), repeat, all_acc(1,WatchList), select_from_sockets(20000,[Acc|WatchList],ReceivedList), member(Sock,ReceivedList), rec_do(Acc,Sock,Data), write(Sock=Data),nl, name(AData,Data), socket_send(Sock,AData), fail. rec_do(A,A,_):- !,server_accept(A,Host,S),assert('$acc$'(S)),fail. rec_do(_,S,D):- socket_receive_list(S,D),length(D,N),N>0,!. rec_do(_,S,_):- socket_close(S),retract('$acc$'(S)),fail. all_acc(N,[A|L]):- clause('$acc$',1,N,'$acc$'(A)),!,NN is N+1,all_acc(NN,L). all_acc(_,[]). ?-go. 4=[72,101,108,108,111]
UNIXソケットサーバーのサーバー生成述語を定義し、その後述語を実行しクライアントからの接続待機を行う。
上記の例ではUNIXソケットサーバーをUNIXソケット(/tmp/test.sock)で生成し、クライアントからの接続を待機する。
その後、クライアントからの接続が確立された場合は、データ受信を行い受信データをリストで表示しクライアント側へ受信データを返信している。
test:- unix_client_connect('/tmp/test.sock',S), socket_send(S,'Hello'), get_all(S,"""",LAns), name(Ans,LAns), write(Ans),nl, socket_close(S). get_all(Sock2,Bef,Ans):- select_from_sockets(20000,[Sock2],[Sock3]), socket_receive_list(Sock3,Out),length(Out,N),N>0,!, append(Bef,Out,NextBef), get_all(Sock3,NextBef,Ans). get_all(Sock2,A,A). ?-test. Hello yes ?-
UNIXソケットサーバーへ接続しデータを送受信する述語を定義し、その後述語を実行しUNIXソケットサーバー間でデータの送受信を行う。
上記の例では、UNIXソケット(/tmp/test.sock)でUNIXソケットサーバーに接続しデータを送信している。
その後、UNIXソケットサーバーからのデータを受信し、受信データを表示している。
test:- client_connect('127.0.0.1','5000',S), repeat, s_sleep(100), check_socket_sendable(S), socket_send(S,'Client Data'), repeat, s_sleep(100), check_socket_receivable(S), socket_receive(S,Data), write(Data),nl, socket_close(S). ?-test. Server Data yes ?-
上の項目まで説明してきたsendやreceiveなどは、全てブロッキング処理になり、sendの場合は「相手が受信できる状態までブロックする」、receiveの場合は「相手からのデータが届くまでブロックする」。
一つのソケットのやり取りを行うのであれば、ブロッキング処理でも問題ありませんが、複数のソケットを受信する場合や、受信待ちの間に別の作業を挟みたい場合はノンブロッキング処理を使用する必要があります。
socket_send の前に置き、相手が受信できない状態であればfailする。相手が受信可能であれば成功し、次に続くsend処理もノンブロッキングで実施される。
check_socket_receivable(S)socket_receive の前に置き、ソケット宛の受信データが来ていない場合はfailする。受信データがあれば成功し、receive処理が実施できる。
上記の例では、ソケットサーバー(127.0.0.1)に5000ポートで接続し、接続後送信可能確認を行い、送信できる状態であればデータ送信、出来なければsleepしながら繰り返し送信確認。
送信後、受信データがデータを受信、なければsleepしながら繰り返し受信確認、データの受信後、データを表示している。
注意) 現在ノンブロッキング処理は非SSLのAグループとEグループでしか使用できません。
test1:- ping('127.0.0.1',2). ?-test1. yes test2:- ping_async('127.0.0.1',S), repeat, s_sleep(100), check_socket_receivable(S), socket_receive_list(S,L), write(receive=L),nl, length(L,Len), (Len > 0->write('Replay');write('No Replay')), socket_close(S). ?-test2. receive=[69,0,0,28,140,241,64,0,64,1,175,237,127,0,0,1,127,0,0,1,8,0,247,255,0,0,0,0] Replay yes ?-
ping(Server,Timeout)はサーバーに対しpingを実施、Timeout(秒)値以内で応答があれば成功し、なければfailします。
ping_async(Server,Socket)はICMPを送るとともにソケットを生成、ノンブロッキング処理で相手からの応答を待ちます。
そのため、ping_asyncの場合はソケット生成後の受信処理、終了処理を必要とします。
上記の例では、1つ目の述語が2秒のタイムアウトでpingの疎通確認を行う。2つ目の述語はソケットの生成を行いながらICMPの送信、 受信はcheck_socket_receivableが成功するまでs_sleepしながら待ち、受信確認ができれば受信データの表示をしている。
注意)ping処理はroot権限でないと使用ができません。
WEBソケットサーバー生成とクライアント接続例
<サーバー側>
nodejsがインストールされていない場合はインストールしておきます。
ダウンロードサイト:http://nodejs.org/
$ cp ~/ダウンロード/node* . $ tar xzf node-v0.10.26.tar.gz $ cd node-v0.10.26 $ ./configure $ make $ sudo make install
パッケージにはnodejsを使ったサーバーのサンプルが含まれています。
これを任意の場所にコピーし、ここにwebsocketモジュールをインストールします
$ cp -r /usr/local/share/azprolog/sample/ext/websock_node_server .
$ cd websock_node_server
$ npm install websocket
SSLを使用しない場合のサーバー立ち上げ
$ node sample.js
SSL使用、クライアント認証付きのサーバー立ち上げ
$ node sample-client-cert.js
<クライアント側>
パッケージにAZ-PrologのWebソケットを使ったクライアントのサンプルが含まれています。
$ cd /usr/local/share/azprolog/sample/ext/
$ prolog -s websock.pl
| ?- t. % ssl を使用しない場合
<サーバーとの通信テストが開始され、画面に内容が表示されます。>
:
| ?- t2. % SSL使用、クライアント認証付き
<サーバーとの通信テストが開始され、画面に内容が表示されます。>
処理のそれぞれの詳細はプログラムをご一読ください。