MyEnigma

とある自律移動システムエンジニアのブログです。#Robotics #Programing #C++ #Python #MATLAB #Vim #Mathematics #Book #Movie #Traveling #Mac #iPhone

LinuxにおけるTCPソケット通信を利用したプロセス間通信

 

プロセス間通信の必要性

大規模なソフトウェアを作成しようとすると、

プロセス間通信の機能が欲しくなります。

複数のソフト(プロセス)を同時に走らせ、

それらのプロセスがデータを通信しあうことによって、

複数のプログラムによる協調駆動を元にした

大規模ソフトを作成することができるのです。


またこのような

プロセス間通信を元にした

ソフトウェアの設計をすることにより、

ソフトウェアのモジュール化が進み、

ソフトの再利用性が向上したり、

マルチコアやハイパースレッディングに対応した

最近のCPUのリソースを最大限に利用することができます。

また、今回紹介するTCP/IPのソケット通信などを利用することにより

複数台のコンピュータに跨るソフトウェアを作成することができ、

ハードウェアを抽象化するソフトも作成することができます。


TCPを使用したプロセス間通信

プロセス間通信を実現する方法はいくつかありますが、

その内一つはTCP/UDPを使用した方法です。

TCP/UDPは現在のインターネットで採用されている

通信プロトコルで、

インターネットに接続できないPCが殆どいないのと同様に

TCP/UDPを使用することができないPCは殆どいないといえるほど

一般的な方法です。


その中でもTCPは、データの送受信の管理や

データの抜けや順番のチェックなど

通信をする上で一番面倒な部分を

すべてTCP自身が実施してくれるプロトコルです。


ユーザは通信のことを考えなくて良くなり、

メインのアプリに集中することができます。


詳しいTCPの概要に関しては冒頭の参考文献を

参考にしてもらいたいと思います。

(ちなみ冒頭の本は、

TCP/IPだけの本かと思われますが

コンピュータによる通信のバイブルと言われるほどの

名著で、わかりやすく非常にオススメです)

C++でTCP通信用ライブラリの使い方

今回、Linuxにおいて、

C++によるTCP通信用のライブラリを作成してみました。

この記事の一番下にGist上のコードを載せておきます。


コードを見ると分かる通り、

TCPのサーバ用のクラスとクライアント用のクラスが定義されている

ヘッダライブラリです。

ヘッダライブラリなので、インクルードするだけで使用できます。


使い方はそれぞれのクラスのヘッダコメントに書いてありますが、

まず初めにプロセス間通信をしたい2つのプログラムを準備し、

片方をサーバとして、サーバクラスを下記のように使用します。

TcpServer server;//TCPサーバ用オブジェクト
int PORT=50001;//サーバのポート番号
server.Init(PORT);//初期化

ポート番号はプログラムの名前みたいなものなので、

自由に使用可能な49152–65535の中で一つの値を選びます。

TCPやUDPにおけるポート番号の一覧 - Wikipedia


するとサーバ側がクライアントのコネクト待ち状態になります。



続いて、もう片方のプログラムをクライアントとして、

クライアントクラスを下記のように使用します。

TcpClient client;//TCPクライアント用オブジェクトの作成
string LOCALHOST="127.0.0.1";//ローカルホストのIPアドレス
int PORT=50001;//ポート番号
client.Init(LOCALHOST,PORT);

この例では、サーバプログラムもクライアントプログラムも

同一のPC内で起動していることとして、

サーバのIPアドレスとローカルホスト(自分自身のPCのIPアドレス)

としています。

また、ポート番号は当然、先ほどのサーバプログラムで指定した

番号と同じものにしなければなりません。



続いてクライアントとサーバが無事接続された場合、

あとは、サーバでもクライアントでも

下記のようにデータを送受信できます。

サーバ:

 vector<char> ReadData;
 int nSend=server.Send(data);  //受信
 
 vector<char> SendData;
 SendData.push_back(0x01);//0x01というデータを送る 
 int nWrite=server.Write(data);//送信

クライアント:

 vector<char> ReadData;
 int nSend=client.Send(data);  //受信
 
 vector<char> SendData;
 SendData.push_back(0x01);//0x01というデータを送る 
 int nWrite=client.Write(data);//送信


便利ですね。

初めてこの方法で通信出来た時はちょっと感動しました(笑)。


また、先ほどの例のクライアントのIPアドレス指定部分を、

適切に設定してあげるだけで、違うPC同士の通信もできます。

Javaでのソケット通信

Javaでソケット通信をする場合は、

  • TCP: Socket.ServerSocket
  • UDP: DtagramSocket

というクラスを使います。

 

ソケット通信のエラーの確認方法

ソケットの関数である,readやwrite,bindなどは、

返り値によってエラーを判断できますが、

ただの数字なので、どのようなエラーが発生したのかがわかりにくいです。


そんな時は下記のライブラリのように、

エラー判定のif文内で、システム関数であるperror関数を呼ぶことで、

発生したエラーに応じて、エラーメッセージが標準エラー出力に出力されます。

perror


perrorの引数である文字列は、

エラーメッセージが表示される時に先頭に表示される文字列で、

エラー判定した関数名とかにしておくと、

どの関数でエラーが発生したのかがわかりやすくなります。


あとは、もしなにかエラーが発生したら、

そのエラーメッセージを読むなり、ぐぐるなりで

対応できるようになると思います。

Address already in use というエラーが発生した場合

うまくソケットの設定を行わないとこのエラーがでます。

Geekなぺーじ:TCPを使う(サーバ、SO_REUSEADDR)

Programming UNIX Sockets in C - Frequently Asked Questions: サーバアプリケーションの作成 (TCP/SOCK_STREAM)


もし出てしまった場合は、5分ほど待つか(おそらく自動で解除されるはず)

下記の方法で、プロセスを殺します。

特定のポートを使用してるプロセスを調べてkillするときの手順メモ。 - NOT SO BAD


下記のコマンドでポートを占有しているプロセスを見つけて、

(0000には作成中のソフトのポート番号を入れます)

lsof -i :0000 


その中からPID(下記の例では111)を見つけて、

killします。

kill 111

そして、もう一度ソフトを起動すれば、先程のエラーは出なくなるはずです。

C++TCP通信用ヘッダライブラリ (Linux)

MyEnigma Supporters

もしこの記事が参考になり、

ブログをサポートしたいと思われた方は、

こちらからよろしくお願いします。

myenigma.hatenablog.com