質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.52%

  • C#

    7103questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Visual Studio

    1831questions

    Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

  • .NET Framework

    457questions

    .NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

  • 非同期処理

    108questions

    非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

  • ソケット

    24questions

    TCP/IPにおいて、IPアドレスとサブアドレスであるポート番号を組み合わせたネットワークアドレスのことを呼びます。また、ソフトウェアアプリケーションにおいて、TCP/IP通信を行う為の仮想的なインターフェースという意味もある。

非同期ソケットを使ったTCPとUDPの通信について

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 686

tuyudaku

score 18

非同期ソケットを使い、対象機器と通信を行うアプリケーションの作成をしています。
対象機器はパソコン等ではありません

実際に作成して、最低限の欲しい動作は確保できたのですが
細かい部分などを実現させようとすると、コードが汚くなってしまいそうだなと思い
拡張性を保てるように、全体のコードを見直そうかなと考えています

考え方の参考のために皆様の意見や知識を貰いたいと思い質問させていただきます。
.NET Frameworkのバージョンは4.5.2です

        public MainForm()
        {            
            // 受信タスクの非同期実行.
            var task = Task.Run(() =>
            {
                StartListening();
            });
        }

        public void StartListening()
        {
            m_Accept.Reset();
            m_Accept.WaitOne();

            try
            {
                while (true)
                {
                    m_Accept.Reset();

                    m_Listener.BeginAccept(new AsyncCallback(AcceptCallback), m_Listener);

                    m_Accept.WaitOne();
                }

            }
            catch
            {
                // 例外処理をどうするか
            }
        }

        public void AcceptCallback(IAsyncResult ar)
        {
            m_Accept.Set();

            Socket Listener;
            Socket Handler;

            try
            {
                Listener = (Socket)ar.AsyncState;
                Handler = Listener.EndAccept(ar);
            }
            catch (Exception)
            {
                return;
            }

            StateObject State = new StateObject();
            State.workSocket = Handler;

            Handler.BeginReceive(State.buffer, 0, StateObject.buffersize, 0, new AsyncCallback(ReadCallback), State);
        }

        public void ReadCallback(IAsyncResult ar)
        {
            int OldIndex = 0;
            int BytesRead = 0;

            try
            {
                StateObject State = (StateObject)ar.AsyncState;
                Socket handler = State.workSocket;

                // クライアントソケットからデータを読み取ります。
                BytesRead = handler.EndReceive(ar);

                // データを受信しているか
                if (BytesRead > 0)
                {
                        /*
                         受信処理
                        */

                        // 再び受信待機をする.
                        handler.BeginReceive(State.buffer, 0, StateObject.buffersize, 0, new AsyncCallback(ReadCallback), State);
                }
                // リードデータが0の場合切断検知
                else
                {
                    /*
                     切断
                    */
                }
            }
            catch (Exception)
            {
                return;
            }
        }

通信に関しては非同期ソケットと検索すると沢山出てくる
BeginAccept、BeginReceiveなどを使っています。

アプリ起動と同時にAcceptを行うためのメソッドを別スレッドに任せて
完全に投げっぱなし状態にしています

アプリからUDPのブロードキャストを使って特定のデータを送り
それを受信した対象機器から接続要求が送られてくる仕組みです
データを送る直前に事前に入力してもらっていた、アプリが動いているPCのIPを元に
ソケットのバインドなどを行うようになっています
アプリ側から接続要求は送りません

一度接続したら、明示的に切断の処理を走らせるまで
接続は維持したまま、受信したデータをその都度処理するために
BeginReceviを繰り返し呼び出すようにしています

直したい点は
・接続要求スレッドの投げっぱなしを辞めたい
接続に失敗したり、IPを変更してやり直したりしたいため
無限ループによる投げっぱなしを辞めたいのですが
何をもってして、スレッドの終了とすればいいのか
送られてきた接続要求が全て処理し終えたらスレッド終了でもいいが
いくつ要求が送られてくるかはわからないし、必ず一斉に送られてくるとも限らない
タイムアウトを導入してもいいがどのように実装するか

・できたら受信処理の部分のBeginReceveの繰り返し呼び出すのもやめたい
理想は何かしらのデータが来たらその都度別スレッドを起こして処理をさせたい
C/C++などのselectのようなものが理想
調べたら出来るそうですが、皆様ならどのように作るかなと思いました

・async/awaitを使った非同期のソケットを導入するべき?
非同期ソケットで検索すると9割がたBeginAcceptを使ったものが出てきますが
async/awaitを使ったほうがコードの記述もすっきりするみたいです
async/awaitの方が新しい技術だと思うのでこっちを使って実装するべきなのかどうか
そもそもselectをつかった実装をする場合必然的にasync/awaitを使うことになるのか

自分の中でも聞きたいことがまとまっていなくてふわふわした感じになってしまって
とても申し訳ないのですが
些細なことでも結構です。糞醜いソースだな!などの意見でも結構です
一人で考えることに限界を感じてきたので、何かしら思い当たることがあったら回答していただけるととても嬉しいです。
よろしくお願い致します。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

スレッドを使うなら、非同期ソケットを使うより、スレッドを立てて同期ソケットを使えばどうでしょう。
そのほうが受信完了、送信エラー検出など見通しが良くなりますぜ

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/02 18:08 編集

    あぁ...
    なんていうか、なんでそんなこと思いつかなかったのかという感じです...
    そもそも、Task.Runを使って別スレッドを用意している時点で
    非同期ソケットを使う必要性がありませんでしたね...

    スレッドを立てるという点に関してなのですが
    C# マルチスレッドなどと検索すると基本的に非同期処理として項目が出てきて
    Task.Ranもしくはasync/awaitなどが出てくるのですが

    C/C++のようにpthread_createを使ってスレッド自体をこちらで管理する
    様なことはC#でも出来るのでしょうか?
    それともC#でスレッドを立てるとなると基本的には
    Task.Runのような形になってしまいますか?

    キャンセル

  • 2018/07/02 18:18

    pthread_createはさすがにC#では使えません。
    そのかわり、非同期実行に関してはいろんな方法が用意されてますので、いろいろやってみてはどうでしょう。

    わたしの中では、
    void threadfunc()
    { 別スレッド処理 }
    とふつーに関数書いておき、
    ((Action)threadfunc).BeginInvoke(null,null);
    とすると別スレッドで実行してくれるのが気に入ってやってます。
    が、多分こんなことしてるのはわたしだけかもしれません

    キャンセル

  • 2018/07/03 09:53

    そんなやり方は探しても無かったです..w
    Actionにそんな使い方があったのですね!勉強になります

    重ねての質問で申し訳ないのですが
    async/awaitの立ち位置?がいまいち分かりません

    Threadの上位互換がTask(上位互換というかWrapper?)というのはなんとなく分かります
    Thread使うならTaskを使えという記事が沢山あるのも理解できるのですが

    TaskじゃなくてAwaitを使えというような記事をたまに見かけるのですが
    正直まだasync/awaitの仕組みをふんわりとしか理解してないので頓珍漢なことを言っているかもしれませんが
    Taskとasync/awaitは完全に使い分けするものではないのかなと思ってしまいます

    私がやろうとしていた、別スレッドでの無限ループを行いたい場合
    async/awaitを使うのは向いていない気がします
    なので使い分けをするのではないのかなと思うのですがどうでしょうか?

    そもそもC#で別スレッドで無限ループ自体ナンセンスとかであれば話は別ですが...

    キャンセル

  • 2018/07/03 10:18

    Async/Awaitは、実はわたしもまだよく理解できてません。
    非同期/同期の違いを意識させないで非同期処理がかける仕組みって程度ですね。
    新しく学ぶ方にはいいんでしょうけど、私なんかは、これは別スレッドの処理なんだ、と意識しないと理解がおっつかない古い(?)人間なんで、そこらへんはこれからぼちぼち学んでいこうかとは思ってます

    > そもそもC#で別スレッドで無限ループ自体ナンセンス
    こっちではガンガン使ってますぜw
    Actionで、ってより、デリゲートにBeginInvokeするとスレッドプールからスレッドを割り当てられますんで(それなりの制限もありますが)無限ループさせるのには便利です
    リソースを握るような処理でなければ、プログラムの終了時には、勝手に殺してくれますし

    キャンセル

  • 2018/07/06 10:49

    >これは別スレッドの処理なんだ、と意識しないと理解がおっつかない
    分かります...
    非同期を同期処理っぽくかけるというのが逆に困るというか...

    >こっちではガンガン使ってますぜw
    なんか安心しましたw

    色々勉強になりました!
    追加の質問などに答えていただきありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.52%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C#

    7103questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Visual Studio

    1831questions

    Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

  • .NET Framework

    457questions

    .NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

  • 非同期処理

    108questions

    非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

  • ソケット

    24questions

    TCP/IPにおいて、IPアドレスとサブアドレスであるポート番号を組み合わせたネットワークアドレスのことを呼びます。また、ソフトウェアアプリケーションにおいて、TCP/IP通信を行う為の仮想的なインターフェースという意味もある。