◆PROCESSING 逆引きリファレンス
カテゴリー:Web・通信
ソケット通信を行うには(サーバ編)
【概要】
PROCESSING公式の通信ライブラリを使う事で、簡単にソケット通信が行えるようになります。
ソケット通信には、TCP/IP(ストリーム通信)とUDP/IP(データグラム通信)がありますが、PROCESSINGの通信ライブラリではTCP/IPをサポートしています。
Javaのライブラリなどで1から作ると小難しい(面倒くさい)処理なのですが、PROCESSINGの通信ライブラリを使えば簡単に実現できます。ビバ!。素晴らしい。
一般的に何らかの要求を送る側をクライアント、要求を待ち受けて処理を実行し、その結果を返す側をサーバと呼びます。
(画像URL:illust-AC 様:acworksさん、wayさん)
ここでは、サーバ側の処理を作る方法を紹介します。クライアント側の処理については「ソケット通信を行うには(クライアント編)」記事を参照してください。
サーバ側のソケットは、Serverクラスのインスタンスとして作成します。
Serverクラスの主なメソッドには、以下のようなものがあります。
番号 | メソッド | 処理概要 |
---|---|---|
1 | active() | Serverソケットが有効か検査します |
2 | available() | Server側で受信すべきデータがあるか検査します |
3 | disconnect() | 接続されたクライアントソケットを切断します |
4 | stop() | ソケットを切断します |
5 | write() | データを送信します |
6 | serverEvent() | 接続イベントを処理します |
7 | disconnectEvent() | 切断イベントを処理します |
なおPROCESSINGの通信ライブラリを使うには、プログラムの先頭に
import processing.net.*;
を記述してください。
【詳細】
Serverインスタンス作成
Server myServer = new Server( PApplet applet, int port, String secondHost ) ;
applet : PAppletインスタンス。通常は this を与える
port : 接続を受け付けるポート番号
secondHost : 複数のNICを搭載している場合、別のホスト名かIPアドレスを与える
クライアントからの要求を待ち受けるポート番号を指定して、サーバ側ソケットを生成します。
ポート番号には、他のサービスと重ならない一意の番号を指定する必要があります。利用できない番号を指定すると、サーバソケット生成時に例外が発生します。
一般的にポート番号は
番号 | 範囲 | 説明 |
---|---|---|
1 | 0–1023 | ウェルノウンポート(予約済みポート) |
2 | 1024–49151 | 登録済みポート |
3 | 49152–65535 | プライベートポート |
のように区分けされています(参考:wikiペディア:TCPやUDPにおけるポート番号の一覧)。
この中で自由に使って良いのは、49152番以降(OSによっては32768番以降)のプライベートポートエリアとなっています。
以下は5204番ポートで待ち受けを行うサーバソケットの生成例です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import processing.net.*; void setup(){ //サーバソケットを生成する //本例ではローカルHOSTの5204番ポートが待ち受け状態 //となる Server myServer = new Server(this, 5204 ); if( myServer.active() == false ){ println("作成失敗"); exit(); } //いろいろな処理 } void draw(){ background(200); } |
ソケットの有効性を確認する
alive : 有効ならTrue
myServer : Serverインスタンス
サーバソケットが有効(生成できた)場合はTrueが戻されます。
受信可能ソケットの有無を検査する
conClient : 受信可能なデータがあるClientインスタンス
myServer : Serverインスタンス
受信可能なソケットがあるか調べます。受信可能な接続済みソケットがある場合、該当データを送ってきたクライアントソケットのインスタンスが戻されます。
受信可能なソケットがない場合は、null が戻されます。
以下はサーバソケットを生成後、受信可能なソケットがあるか調べながら読み取り処理を行う例です。
データの受信は、戻されたClientインスタンスのメソッド(readBytesなど)を利用します。Clientの使い方については「ソケット通信を行うには(クライアント編)」記事を参照してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import processing.net.*; Server myServer; void setup(){ //サーバソケットを生成する //本例ではローカルHOSTの5204番ポートが待ち受け状態 //となる myServer = new Server(this, 5204 ); if( myServer.active() == false ){ println("作成失敗"); exit(); } //いろいろな処理 } void draw(){ //受信可能ソケットがあるか調べる Client conClient = myServer.available(); if( conClient != null ){ println("受信可能なソケットがあります"); int recvSize = conClient.available(); if ( recvSize > 0) { //受信する byte[] recvData = conClient.readBytes( recvSize ); println("受信しました :" + recvData.length ); } } } |
送信する
sendData : 送信データ
myServer : Serverインスタンス
接続済みのクライアントソケットにデータを書き込みます。
本メソッドは、該当サーバへ接続済みのすべてのクライアントソケットに対して、データを送信する事に注意してください。
特定のクライアントに向けてデータを送信したい場合は、serverEvent() などで接続してきたクライアントソケットを取得し、該当クライアントに対して write() を行う必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import processing.net.*; Server myServer; void setup(){ size(200,200); //サーバソケットを生成する //本例ではローカルHOSTの5204番ポートが待ち受け状態 //となる myServer = new Server(this, 5204 ); if( myServer.active() == false ){ println("作成失敗"); exit(); } //いろいろな処理 } void draw(){ } void mouseClicked(){ //データを送信する byte[] sendData = new byte[256]; myServer.write( sendData ); } |
上記例はマウスクリック時に、その時点で接続済みのすべてのクライアントソケットにデータを送信する例です。
ソケットを切断する
myServer : Serverインスタンス
待受中のソケットを閉じます。ソケットを閉じると、再度ソケットを生成するまで、そのソケットでの待ち受けを行うことはできません。
ソケットを切断すると、コンソール領域に
「Server SocketException: socket closed」
のような赤いメッセージが表示されますが、これは異常ではありません。
接続イベントを処理する
evtServer : イベントが発生したサーバソケット
conClient : イベントが発生したクライアントソケット
クライアント側からの接続が発生した場合、serverEvent 関数が呼び出されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import processing.net.*; Server myServer; void setup(){ size(200,200); //サーバソケットを生成する //本例ではローカルHOSTの5204番ポートが待ち受け状態 //となる myServer = new Server(this, 5204 ); if( myServer.active() == false ){ println("作成失敗"); exit(); } //いろいろな処理 } void draw(){ } //接続を検知したときに呼び出されるイベント関数 void serverEvent(Server evtServer, Client conClient ){ println( conClient.ip() + " から接続がありました。"); //接続先にデータを送信する byte[] sendData = new byte[256]; conClient.write( sendData ); } |
上記は接続イベントが発生した際に、接続してきたクライアントにデータを送信する例です。
切断イベントを処理する
disClient : イベントが発生したクライアントソケット
接続済みのクライアントソケットが破棄された場合、disconnectEvent 関数が呼び出されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import processing.net.*; Server myServer; void setup(){ size(200,200); //サーバソケットを生成する //本例ではローカルHOSTの5204番ポートが待ち受け状態 //となる myServer = new Server(this, 5204 ); if( myServer.active() == false ){ println("作成失敗"); exit(); } //いろいろな処理 } void draw(){ } //切断を検知したときに呼び出されるイベント関数 void disconnectEvent(Client disClient) { println( disClient.ip() + " が切断しました。"); } |
【関連記事】
サンプルプログラム
イメージを送信する例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
/** * PROCESSING 3.0 Server/Client Sample * サーバ側処理例 * @auther MSLABO * @since 2019/06 1.0 */ import processing.net.*; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; Server myServer; PImage sendImage; byte[] sendData; void setup(){ size( 300,300 ); textSize( 32 ); textAlign(LEFT,TOP); fill(255,255,0); //サーバソケットを生成する //本例ではローカルHOSTの5204番ポートが待ち受け状態 //となる myServer = new Server(this, 5204 ); if( myServer.active() == false ){ println("作成失敗"); exit(); } //送信対象イメージを読み込む sendImage = loadImage("witch.png"); Path file = Paths.get( dataPath( "witch.png" ) ); try{ sendData = Files.readAllBytes( file ); } catch( IOException e ){ e.printStackTrace(); } } void draw(){ background( sendImage ); text( "Server", 0, 0 ); } //接続があったクライアントにイメージデータを送る void serverEvent(Server someServer, Client conClient) { println( "接続先にデータを送信:" + sendData.length ); conClient.write( sendData ); } |
接続があったクライアントに、イメージデータを送信します。
<出力サンプル>
(画像URL:illust-AC 様:くみた柑さん)
対応するクライアント側のサンプルは、以下のようになります。利用しているクライアントソケット命令の詳細については、「ソケット通信を行うには(クライアント編)」記事を参照してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
/** * PROCESSING 3.0 Server/Client Sample * クライアント側処理例 * @auther MSLABO * @since 2019/06 1.0 */ import processing.net.*; import java.awt.image.BufferedImage; import javax.imageio.ImageIO; import java.io.ByteArrayInputStream; import java.awt.Image; Client myClient; PImage recvImage; boolean recvFlg; void setup(){ size( 300,300 ); textSize( 32 ); textAlign(LEFT,TOP); fill(0,0,255); //クライアントソケットを生成する //本例ではローカルHOSTの5204番ポートが待ち受け状態 //でない場合、例外となる myClient = new Client(this,"127.0.0.1", 5204 ); //未受信にする recvFlg = false; } void draw(){ background(200); //未受信なら受信データを確認し、 //受信済みなら表示する if( recvFlg == false ){ //未受信 recvCheckAndConvertImage(); } else { //受信済み recvImage.resize( width, height ); image( recvImage, 0, 0 ); text( "Client", 0, 0 ); } } //受信データがあるか検査し、データをイメージ変換する void recvCheckAndConvertImage(){ int readBytes = myClient.available(); if( readBytes > 0 ){ //受信データがある場合 byte[] recvData = myClient.readBytes( readBytes ); //受信データをイメージ変換する try{ BufferedImage bImg = ImageIO.read(new ByteArrayInputStream(recvData)); Image img = (Image)bImg; recvImage = new PImage(img); recvFlg = true; }catch( Exception e ){ e.printStackTrace(); } } } |
本ページで利用しているアイコン画像は、下記サイト様より拝借しております。各画像の著作権は、それぞれのサイト様および作者にあります。