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

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

ただいまの
回答率

87.61%

DoEventsを使用せずにDoLoopを抜ける方法

解決済

回答 5

投稿

  • 評価
  • クリップ 0
  • VIEW 1,771

score 1

vb.netを使用してTcpClientの作成をしています。
データ送信ボタンを押すと、切断ボタンが押されるまでデータをループで送り続ける使用になっています。
Application.DoEvents()
If flg = true Then Exit Do
上記でDoLoopを抜けていたのですが、DoEventsの処理を使ってはいけないと言われました。
そのため、非同期処理 async/await を使用しようと思いましたが上手く実装できませんでした。
どのようにすれば私の思う事を実装できるか、DoEventsは本当に不必要なのか、
async/awaitで実現できるのか、教えて頂けませんでしょうか。

以下現在のソースです

Public Class Form1

    Private m_tcp As System.Net.Sockets.TcpClient
    Private flg As Boolean

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

        Dim IP As String
        Dim Port As Integer
        IP = TextBox1.Text
        Port = Integer.Parse(TextBox2.Text)

        m_tcp = New System.Net.Sockets.TcpClient(IP, Port)
        Console.WriteLine("サーバー({0}:{1})と接続しました({2}:{3})。", _
            DirectCast(m_tcp.Client.RemoteEndPoint, System.Net.IPEndPoint).Address, _
            DirectCast(m_tcp.Client.RemoteEndPoint, System.Net.IPEndPoint).Port, _
            DirectCast(m_tcp.Client.LocalEndPoint, System.Net.IPEndPoint).Address, _
            DirectCast(m_tcp.Client.LocalEndPoint, System.Net.IPEndPoint).Port)

    End Sub

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click

        If m_tcp Is Nothing Then
            Exit Sub
        End If

        Console.WriteLine("送信開始")

        Dim ns As System.Net.Sockets.NetworkStream = m_tcp.GetStream()

        ns.ReadTimeout = 10000
        ns.WriteTimeout = 10000

        Dim text As Long
        Dim bytedata() As Byte
        flg = False

        Do

            Dim sendBytes(49) As Byte
      
      ーーー配列の処理ーーー

            ns.Write(sendBytes, 0, sendBytes.Length)
            Dim i As Integer
            For i = 0 To 119
                Console.Write(sendBytes(i) & ", ")
            Next i
            Dim textFile As System.IO.StreamWriter
            textFile = New System.IO.StreamWriter("C:\Users\G570\Desktop\Tcp\TcpClient\6月8日\log.txt", True, System.Text.Encoding.Default)
            For i = 0 To 119
                textFile.Write(sendBytes(i) & ", ")
            Next i
            textFile.WriteLine() 
            textFile.Close() 
            Array.Clear(sendBytes, 0, sendBytes.Length)
            System.Threading.Thread.Sleep(5000)
            Application.DoEvents()
            If flg = True Then Exit Do

        Loop

    End Sub

    Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click

        flg = True

        m_tcp.Close()
        Console.WriteLine("切断しました。")

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • maisumakun

    2020/06/10 09:33

    「DoEventsの処理を使ってはいけない」理由は確認しましたか?

    キャンセル

回答 5

checkベストアンサー

0

下記のような感じですかね?
実際には処理中に再度ボタンが押されたなどの考慮が必要になってくるとは思います。

Private cts As CancellationTokenSource

Private Async Sub Button1_Click(sender As Object, e As EventArgs)

    cts = New CancellationTokenSource

    Await Task.Run(Sub()
                        While cts.IsCancellationRequested = False
                            Console.WriteLine($"{Now:HH:mm:ss.fff}")
                            Thread.Sleep(100)
                        End While
                    End Sub)

End Sub

Private Sub Button2_Click(sender As Object, e As EventArgs)
    cts.Cancel()
End Sub

一定間隔でデータを送信するだけみたいですので、タイマーでdo~loopの中身だけ処理するのも手だと思います。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/06/10 17:44

    回答ありがとうございます。
    つまり、DoLoopは使用しなくて良いという事でしょうか?
    ソースを参考に考えてみます!

    キャンセル

0

スレッド化でしょうね。
Button2_Clickイベントのタイミングで、今Button2_Click内で行っている処理をスレッドで起動して抜ける。
それだけでいいはず。
問題はVBAでのスレッド化の難易度ですね。
私はやったことがないですが、ググれば参考になりそうなサイトはあるみたいなので、調べてみてください。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/06/10 17:31

    回答ありがとうございます。
    スレッド化ですか…
    一度調べてみます!

    キャンセル

0

以下参考
時間のかかる処理の進行状況を表示する
バックグラウンド処理を途中でキャンセルするには?[2.0のみ、C#、VB]

DoEventsによる技法は、.NET Frameworkでマルチスレッドプログラミングがサポートされる以前の技法です。
苦肉の策より、サポートされる機能を利用する方が、影響が少なくて済みます。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/06/10 17:37

    回答ありがとうございます。
    DoEventsがサポート以前の技法とは知りませんでした。
    サポートされる機能を利用する方が、影響が少ないなど、その辺をちゃんと調べます。

    キャンセル

  • 2020/06/10 17:53

    提供される機能を利用している分には、その機能に変更があってもそれは提供側でカバーしてくれますが、そうでない場合は影響が無いとは言い切れませんので。

    キャンセル

0

Timerが一番楽だと思います。
Button2_ClickでTimerに繰り返し時間セットしONにて開始。データ送信開始で繰り返し実行。
Button3_ClickでTimerをOFFへセット。Timerストップで終わり。

訂正:
Application.DoEvents()は使わないとダメかもしれません。やってみないと分かりません。
指摘されたのは、Sleepの方と言うことはないでしょうか?

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/06/10 17:41

    回答ありがとうございます。
    Timerは発想にありませんでした。
    指摘されたのはDoEventsのみで、Sleepは何も言われてないです。
    Sleepだと問題があるのでしょうか?

    キャンセル

  • 2020/06/11 08:58 編集

    プログラムを見ますと、
    Button2_Clickで繰り返しのバッチが動きます。
    この繰返しをButton3_Clickで途中停止させる感じに見えます。

    1バッチ処理+Sleep中はホールド状態となり、Button3_Clickからの入力は受付けできません。
    DoEvents()にてForm側へ制御が移りButton3_Clickの入力が可能となります。
    しかしながら、次のバッチが動いてしまう為に、Button3_Clickの入力可能は僅かな時間しかありません。その一瞬を狙ってクリックすれば止まりますが、運用的には厳しいです。
    運用を考えればSleep(5000)の5秒間は、Button3_Clickが押せる状態として、人からの停止指示の判断を待つ様にする方が良いと思われます。
    そのため、ホールドになるSleep(5000)ではなく、1バッチ終了後の5秒間は、別の方法で停止させてクリック入力が出来るようにする指示を受けたのではないかと想像致しました。

    キャンセル

0

  1. 送信処理をメソッド化し、Task.RunでCancellationTokenを渡して起動(送信スレッドとする)
  2. UIスレッドの切断ボタンクリックでCancellationTokenSource.Cancelを実行
  3. 送信スレッドの送信ループ処理をしている所でCancellationToken.IsCancellationRequestedをチェックさせて中断

で中断が実現できると思います。DoEventsは想定外のタイミングでウィンドウメッセージが処理され、フォームイベントが実行されて処理が追いづらくなるので、私は基本的に使わないですね。

vaguely -【C#】Taskをキャンセルする

回答してる間に、YAmaGNZさんと回答が被ってしまいました。YAmaGNZさんのサンプルソースが参考になると思います。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/06/10 17:49

    回答ありがとうございます。
    正直、サンプルソースでは何を行っているか分からなかったため、処理の説明は大変助かります!
    サンプルソースをベースに考えてみます。

    キャンセル

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

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

関連した質問

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