この記事は2020年06月07日に投稿しました。
目次
1. はじめに
こんにちは、iOSのエディタアプリPWEditorの開発者の二俣です。
今回は業務で使用しているC++/CLIでTCPサーバ処理を行う方法についてです。
2. C++/CLIでTCPサーバ処理を行う
C++/CLIでTCPサーバ処理を行うには、TcpListenerクラスを使用します。
以下の実装例のプログラムを実行すると、ターミナルソフトで接続できます。
ターミナルソフトで文字を入力し改行コードを入力すると、サーバから入力した文字の先頭に"->"が付加されて送信されます。
実装例では、ターミナルソフトで"\Q"を入力するか、ターミナルソフトを終了させると、サーバも終了します。
実装例
TcpServer.h
#pragma once using namespace System; using namespace System::Threading; using namespace System::Text; public ref class TcpServer { public: TcpServer(int portNo); TcpServer(int portNo, Encoding^ encoding); void StartServer(); private: void Initialize(int portNo, Encoding^ encoding); void ServerThread(); private: //! ポート番号 int mPortNo; //! 文字エンコーディング Encoding^ mEncoding; //! サーバースレッド Thread^ mServerThread; };
TcpServer.cpp
#include "TcpServer.h" #using <system.dll> using namespace System::IO; using namespace System::Text; using namespace System::Net; using namespace System::Net::Sockets; using namespace System::Diagnostics; //! 終了コマンド #define END_COMMAND "\\Q" /** * @brief コンストラクタ * 文字エンコーディングはデフォルトUTF8とします。 * * @param [in] portNo ポート番号 */ TcpServer::TcpServer(int portNo) { Initialize(portNo, Encoding::UTF8); } /** * @brief コンストラクタ * * @param [in] portNo ポート番号 * @param [in] encoding 文字エンコーディング */ TcpServer::TcpServer(int portNo, Encoding^ encoding) { Initialize(portNo, encoding); } /** * @brief 初期化処理を行います。 * * @param [in] portNo ポート番号 * @param [in] encoding 文字エンコーディング */ void TcpServer::Initialize(int portNo, Encoding^ encoding) { mPortNo = portNo; mEncoding = encoding; } /** * @brief サーバーを開始します。 */ void TcpServer::StartServer() { // サーバー処理スレッドを開始します。 ThreadStart^ threadStart = gcnew ThreadStart(this, &TcpServer::ServerThread); mServerThread = gcnew Thread(threadStart); mServerThread->Start(); } /** * @brief サーバースレッド処理 */ void TcpServer::ServerThread() { TcpListener^ listener = nullptr; try { // TCPリスナーを生成し、開始します。 listener = gcnew TcpListener(IPAddress::Any, mPortNo); listener->Start(); // クライアントからの接続待ちにします。 TcpClient^ client = listener->AcceptTcpClient(); // クライアントの接続後、受信と送信のストリームを生成します。 NetworkStream^ stream = client->GetStream(); StreamReader^ reader = gcnew StreamReader(stream, mEncoding); StreamWriter^ writer = gcnew StreamWriter(stream, mEncoding); // 終了コマンド(\Q)を受信するまでループします。 while (true) { // クライアントからのデータ受信待ち。 String^ data = reader->ReadLine(); // クライアントから切断された場合 if (data == nullptr) { // ループを終了します。 break; } // 受信データが終了コマンド(\Q)の場合 if (data->ToUpper()->Equals(END_COMMAND)) { // ループを終了します。 break; } // 受信したデータをクライアントに送信します。 // Flushしないと送信されません。 writer->WriteLine("->" + data); writer->Flush(); } } catch (Exception^ e) { Debug::WriteLine(e->Message); } finally { try { if (listener) { listener->Stop(); } } catch (Exception^ e) { Debug::WriteLine(e->Message); } } }
main.cpp
#include "TcpServer.h" using namespace System; int main() { // ポート番号1234でTCPサーバーを生成し、開始します。 TcpServer^ server = gcnew TcpServer(1234); server->StartServer(); return 0; }
API Reference
TcpListenerクラス
3. おわりに
C++/CLIでTCP通信処理を行う必要があり、その方法を調べました。
紹介している一部の記事のコードはGitlabで公開しています。
興味のある方は覗いてみてください。
私が勤務しているニューラルでは、主に組み込み系ソフトの開発を行っております。
弊社製品のハイブリッドOS Bi-OSは高い技術力を評価されており、特に制御系や通信系を得意としています。
私自身はiOSモバイルアプリやウィンドウズアプリを得意としております。
ソフトウェア開発に関して相談などございましたら、お気軽にご連絡ください。
また一緒に働きたい技術者の方も随時募集中です。
興味がありましたらご連絡ください。
EMAIL : info-nr@newral.co.jp / m-futamata@newral.co.jp
TEL : 042-523-3663
FAX : 042-540-1688