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

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

新規登録して質問してみよう
ただいま回答率
85.50%
C#

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

Visual Studio

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

ソケット

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

非同期処理

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

.NET Framework

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

Q&A

解決済

1回答

12297閲覧

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

tuyudaku

総合スコア75

C#

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

Visual Studio

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

ソケット

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

非同期処理

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

.NET Framework

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

0グッド

2クリップ

投稿2018/07/02 08:46

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

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

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

C#

1 public MainForm() 2 { 3 // 受信タスクの非同期実行. 4 var task = Task.Run(() => 5 { 6 StartListening(); 7 }); 8 } 9 10 public void StartListening() 11 { 12 m_Accept.Reset(); 13 m_Accept.WaitOne(); 14 15 try 16 { 17 while (true) 18 { 19 m_Accept.Reset(); 20 21 m_Listener.BeginAccept(new AsyncCallback(AcceptCallback), m_Listener); 22 23 m_Accept.WaitOne(); 24 } 25 26 } 27 catch 28 { 29 // 例外処理をどうするか 30 } 31 } 32 33 public void AcceptCallback(IAsyncResult ar) 34 { 35 m_Accept.Set(); 36 37 Socket Listener; 38 Socket Handler; 39 40 try 41 { 42 Listener = (Socket)ar.AsyncState; 43 Handler = Listener.EndAccept(ar); 44 } 45 catch (Exception) 46 { 47 return; 48 } 49 50 StateObject State = new StateObject(); 51 State.workSocket = Handler; 52 53 Handler.BeginReceive(State.buffer, 0, StateObject.buffersize, 0, new AsyncCallback(ReadCallback), State); 54 } 55 56 public void ReadCallback(IAsyncResult ar) 57 { 58 int OldIndex = 0; 59 int BytesRead = 0; 60 61 try 62 { 63 StateObject State = (StateObject)ar.AsyncState; 64 Socket handler = State.workSocket; 65 66 // クライアントソケットからデータを読み取ります。 67 BytesRead = handler.EndReceive(ar); 68 69 // データを受信しているか 70 if (BytesRead > 0) 71 { 72 /* 73 受信処理 74 */ 75 76 // 再び受信待機をする. 77 handler.BeginReceive(State.buffer, 0, StateObject.buffersize, 0, new AsyncCallback(ReadCallback), State); 78 } 79 // リードデータが0の場合切断検知 80 else 81 { 82 /* 83 切断 84 */ 85 } 86 } 87 catch (Exception) 88 { 89 return; 90 } 91 }

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

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

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

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

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

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

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

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

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

投稿2018/07/02 08:53

y_waiwai

総合スコア87719

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tuyudaku

2018/07/02 09:11 編集

あぁ... なんていうか、なんでそんなこと思いつかなかったのかという感じです... そもそも、Task.Runを使って別スレッドを用意している時点で 非同期ソケットを使う必要性がありませんでしたね... スレッドを立てるという点に関してなのですが C# マルチスレッドなどと検索すると基本的に非同期処理として項目が出てきて Task.Ranもしくはasync/awaitなどが出てくるのですが C/C++のようにpthread_createを使ってスレッド自体をこちらで管理する 様なことはC#でも出来るのでしょうか? それともC#でスレッドを立てるとなると基本的には Task.Runのような形になってしまいますか?
y_waiwai

2018/07/02 09:18

pthread_createはさすがにC#では使えません。 そのかわり、非同期実行に関してはいろんな方法が用意されてますので、いろいろやってみてはどうでしょう。 わたしの中では、 void threadfunc() { 別スレッド処理 } とふつーに関数書いておき、 ((Action)threadfunc).BeginInvoke(null,null); とすると別スレッドで実行してくれるのが気に入ってやってます。 が、多分こんなことしてるのはわたしだけかもしれません
tuyudaku

2018/07/03 00:53

そんなやり方は探しても無かったです..w Actionにそんな使い方があったのですね!勉強になります 重ねての質問で申し訳ないのですが async/awaitの立ち位置?がいまいち分かりません Threadの上位互換がTask(上位互換というかWrapper?)というのはなんとなく分かります Thread使うならTaskを使えという記事が沢山あるのも理解できるのですが TaskじゃなくてAwaitを使えというような記事をたまに見かけるのですが 正直まだasync/awaitの仕組みをふんわりとしか理解してないので頓珍漢なことを言っているかもしれませんが Taskとasync/awaitは完全に使い分けするものではないのかなと思ってしまいます 私がやろうとしていた、別スレッドでの無限ループを行いたい場合 async/awaitを使うのは向いていない気がします なので使い分けをするのではないのかなと思うのですがどうでしょうか? そもそもC#で別スレッドで無限ループ自体ナンセンスとかであれば話は別ですが...
y_waiwai

2018/07/03 01:18

Async/Awaitは、実はわたしもまだよく理解できてません。 非同期/同期の違いを意識させないで非同期処理がかける仕組みって程度ですね。 新しく学ぶ方にはいいんでしょうけど、私なんかは、これは別スレッドの処理なんだ、と意識しないと理解がおっつかない古い(?)人間なんで、そこらへんはこれからぼちぼち学んでいこうかとは思ってます > そもそもC#で別スレッドで無限ループ自体ナンセンス こっちではガンガン使ってますぜw Actionで、ってより、デリゲートにBeginInvokeするとスレッドプールからスレッドを割り当てられますんで(それなりの制限もありますが)無限ループさせるのには便利です リソースを握るような処理でなければ、プログラムの終了時には、勝手に殺してくれますし
tuyudaku

2018/07/06 01:49

>これは別スレッドの処理なんだ、と意識しないと理解がおっつかない 分かります... 非同期を同期処理っぽくかけるというのが逆に困るというか... >こっちではガンガン使ってますぜw なんか安心しましたw 色々勉強になりました! 追加の質問などに答えていただきありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問