今回は最近社内の勉強会のために調べたC++とC#でのプロセス間通信をソケット通信のTCPプロトコルで行ってみようと思います。
※Visual Studio2019で今回のプロジェクトを作成しています。
初めにプロセス間通信とは
まず、初めにプロセス間通信とは何かというのを説明出来ればと思います。
簡単に言えば違うプロセスで動いているプログラム同士で通信を行い情報をやり取りしていくような処理になります。
例えばC#で作ったツールでパラメータの変更を行い、C++のゲーム部分に反映する事によりパラメーターを変更する度にコンパイルをする事等が防ぐ事が出来ます。
プロセス間通信には調べたところ大きく分けて3通りあるようです。
・ソケット通信
・パイプライン通信
・共有メモリ
今回は上記の中のソケット通信でプロセス間通信を行おうと思います。
まずはホストを建てよう
通信を行うのでホストとクライアントが必要となります。
今回はVisual StudioのC++のコンソールアプリでプロジェクトを作り、
C++でホスト処理を書きました。
#include <stdio.h>
#include <WinSock2.h>// WinSocketを使用するためのInclude
#include <WS2tcpip.h>// WinSocketを使用するためのInclude
// WinSocketを使用するためのlibファイル
#pragma comment(lib, "ws2_32.lib")
int main()
{
WSADATA wsaData;
SOCKET sockListen;
// Winsockの初期化
WSAStartup(WINSOCK_VERSION, &wsaData);
struct sockaddr_in addr;
// AF_INETを渡すことによりIPv4で通信する事を指定
addr.sin_family = AF_INET;
// ポート番号を指定好きなポートを指定してください。
addr.sin_port = htons(12345);
// INADDR_ANYを指定する事によりどのIPからでも通信を受け取る状態にする。
addr.sin_addr.S_un.S_addr = INADDR_ANY;
// ソケットを作成
sockListen = socket(addr.sin_family, SOCK_STREAM, 0);
// ソケットの作成に失敗していないかどうか
if (sockListen == INVALID_SOCKET)
{
printf("socket failed\n");
return -1;
}
// ソケットにアドレスを割り当てる
if (bind(sockListen, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
{
printf("bind:エラー");
return -1;
}
// ソケットを接続待ち状態にする
if (listen(sockListen, 5) == SOCKET_ERROR)
{
printf("listen:エラー");
return -1;
}
SOCKET sock;
struct sockaddr_in client;
int clientlen = sizeof(client);
char buf[256];
memset(buf, 0, sizeof(buf));
// クライアントからの接続を待つ
sock = accept(sockListen, (struct sockaddr*)&client, &clientlen);
printf("接続完了\n");
// クライアントからデータを受け取る
recv(sock, buf, sizeof(buf), 0);
// 受け取った文字を表示
printf("%s\n", buf);
// ソケット通信を終了
closesocket(sock);
// Winsockを終了
WSACleanup();
return 0;
}
・14行目はWinSocketの初期化で、1つ目の引数でWinSocketのバージョンを
選択する事が出来ます。
WINSOCK_VERSIONで最新のバージョンを指定できます。
今回であれば2.2を使用しています。
・25行目でソケットを作成しています。2つ目の引数でSOCK_STREAMを渡す
事によりTCP通信でソケット通信をします。
次はクライアントの処理を書こう
次はVsual StudioでC#のコンソールアプリでプロジェクトを作成し、
C#でクライアントの処理を書いてみました。
using System;
using System.Text;
using System.Net.Sockets; // Socket通信をするための名前空間
namespace TestClient
{
class Program
{
static int Main(string[] args)
{
// TcpClientを使ってホストに対し接続を試みる
TcpClient client = new TcpClient();
client.Connect("127.0.0.1", 12345);
// コマンドラインで入力された文字を取得
char[] input = Console.ReadLine().ToCharArray();
// 入力された文字をbyteに変換して送信する
NetworkStream stream = client.GetStream();
byte[] bytes = Encoding.ASCII.GetBytes(input);
stream.Write(bytes, 0, bytes.Length);
// TcpClientを終了
client.Close();
return 0;
}
}
}
・13行目でホストとの接続を試みています。
1つめの引数でIPを渡します。
IPで127.0.0.1は自分自身のIPを指すことになります。
・2つ目の引数はポート番号です。
これはホストのポート番号に合わせ12345と入力しています。
実行結果
まず、C++で組んだプロジェクトを先に起動します。
次にC#のプロジェクトを起動します。
すると以下のようにC++プロジェクト側に接続完了と表示されました。
次にC#側のプロジェクトで表示したコンソールに好きな英数字を入力します。
自分はlogicalbeatと入力しました。
Enterを押し、C++側のコンソール画面を見るとlogicalbeatと表示されました。
問題なくプロセス間通信が出来ている事が確認できました。
まとめ
今回ローカル上で簡単なソケット通信でのプロセス間通信を行いました。
上記で話した通り、ツールの結果を他のプロセスに使用したい場合等にプロセス間通信を行うのが主な方法かなと思います。
異なる言語の通信であっても今回のブログのように簡単な処理で通信を行う事が出来るので是非試してみて下さい。
【免責事項】
本サイトでの情報を利用することによる損害等に対し、
株式会社ロジカルビートは一切の責任を負いません。