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

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

ただいまの
回答率

90.34%

  • C#

    9682questions

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

[C#]ソケット通信プログラムの構築について

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 4,399

ryo_se

score 72

現在ソケット通信を使用したプログラムを作成しております。

http://note.chiebukuro.yahoo.co.jp/detail/n1656
上記Webサイトを参考にし、Socketクラスを用いてサーバーとクライアント間での通信を行う基本的なプログラムは作成しました。

ですが、カスタムをしていく上で下記の実現ができず困っております。

1、1つのサーバーに対し、複数のクライアントから接続を行えるようにしたい。
2、サーバーが電文受信待機状態(SocketクラスのReciveメソッド)になっている時に、受信を中断 or 停止させたい。(勿論再開も)
3、サーバと接続中のクライアントの通信が切断され、その後クライアントの通信状態が回復した時、サーバと再接続を試みたい。

コードの詳細はURL先を見ていただければと思いますが、
Reciveメソッドについて調べたところ、中断や停止が無い様に見受けられました。

またサーバ側の流れとして下記となっています。
①クライアントとの接続待機(Acceptメソッド)
②クライアントと接続確立後、電文受信待機(Reciveメソッド)

3に関しては、上記状態になった際に電文受信待機でブロッキングされていることから、再度接続待機が行えない状態になっているのだと思います。

3つの実現に対し、サンプルやご教示をいただければ幸いです。

【追記】
複数クライアントの接続について、下記サイトを参考にしてコーディングしてみました。
https://codezine.jp/article/detail/22

上記サイトのサンプルではクライアントと接続ができたら即座にクローズしていますが、
今回は接続中のままとしています。

ところが接続中の複数のクライアントを管理、電文を送信するために、接続したSocketインスタンスをListに入れて保存という形をとってみましたが、一定時間毎にListにSocketインスタンスが追加されていってしまいます。

そもそも複数のクライアントを管理する上で正しい方法がわからず、ご教示をいただきたいです。

private Socket ServerSocket = null;
        private System.Net.IPEndPoint EndPointHost = null;        //エンドポイント
        private List<Socket> ConnectSocketArray = new List<Socket>(); 

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        //クライアントの接続待ちスタート
        private void StartAccept(System.Net.Sockets.Socket server)
        {
            //接続要求待機を開始する
            server.BeginAccept(
                new System.AsyncCallback(AcceptCallback), server);
        }

        //BeginAcceptのコールバック
        private void AcceptCallback(System.IAsyncResult ar)
        {
            //サーバーSocketの取得
            System.Net.Sockets.Socket server =
                (System.Net.Sockets.Socket)ar.AsyncState;

            //接続要求を受け入れる
            System.Net.Sockets.Socket client = null;
            try
            {
                //クライアントSocketの取得
                client = server.EndAccept(ar);
            }
            catch
            {
                System.Console.WriteLine("閉じました。");
                return;
            }

            //クライアントが接続した時の処理をここに書く
            //ここでは文字列を送信して、すぐに閉じている
            client.Send(System.Text.Encoding.UTF8.GetBytes("こんにちは。"));
            //client.Shutdown(System.Net.Sockets.SocketShutdown.Both);
            //client.Close();
            ConnectSocketArray.Add(client);

            foreach (Socket cl in ConnectSocketArray)
            {
                Console.WriteLine(cl.ToString());
            }
            Console.WriteLine(ConnectSocketArray.Count());

            //接続要求待機を再開する
            server.BeginAccept(
                new System.AsyncCallback(AcceptCallback), server);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // Socket の生成
            ServerSocket = new Socket(
            AddressFamily.InterNetwork,  // IP version 4 のアドレス
            SocketType.Stream,            // 通信方式をバイトストリーム
            ProtocolType.Tcp);            // プロトコルをTCP

            // EndPointHostがnullならば、ホストのIPアドレスとポート番号の指定
            if (EndPointHost == null)
            {

                EndPointHost = new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 10002);
            }

                        // ローカル エンドポイント(IPアドレス等の情報)と関連付け
            ServerSocket.Bind(EndPointHost);
            // 電文取り出しの接続がまだ保留中におけるキューの最大長
            ServerSocket.Listen(100);

            StartAccept(ServerSocket);
            Console.WriteLine("待機状態になりました");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            ServerSocket.Shutdown(SocketShutdown.Both);
            ServerSocket.Close();
            ServerSocket= null;
            Console.WriteLine("待機状態終了しました");

        }

        //テキストボックスの内容を送信する
        private void button3_Click(object sender, EventArgs e)
        {
            string data = textBox1.Text;
            foreach(Socket client in ConnectSocketArray){
                client.Send(System.Text.Encoding.UTF8.GetBytes(data));
            }

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

0

コードを参考にするならば、
Nonsoft さん:通信ツール(RS232C TCP/IP UDP/IP)
ここで紹介されている、TCPサーバーのコードは、上手に拡張してあげると、
簡単に10~20のクライアント対応になります。

TCP 状態変化は、
TCP 状態遷移 などで、検索してみてください。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/06/22 12:43

    http://homepage2.nifty.com/nonnon/SoftSample/CS.NET/SampleTcpIp.html

    上記を見てみましたがうまくできませんでした・・。
    また今回、クライアント側はコネクションを張ったら、電文を送信してもコネクションは切らず、指示があるまではコネクションを張りっぱなしの方針で実装したいと思っています。

    キャンセル

  • 2016/06/22 15:07 編集

    >上記を見てみましたがうまくできませんでした・・。
    VS2010 / 2015 Professional C# で、
    再現方法を確認してみますね。
    >指示があるまではコネクションを張りっぱなしの方針で
    TCP はコネクションして、通信しますので、どちらかの要因で切断しなければ、
    コネクションしたままです。

    キャンセル

  • 2016/06/22 18:01 編集

    Lisner サンプル
    http://homepage2.nifty.com/nonnon/SoftSample/CS.NET/SampleTcpIp.html
    ```C#
    private void button1_Click(object sender, EventArgs e)
    {
    // ソケット送信
    Byte[] dat =
    System.Text.Encoding.GetEncoding("SHIFT-JIS").GetBytes("abcあいう");
    objStm.Write(dat, 0, dat.GetLength(0));
         //↑ここで拒否や、送信できないエラーになる場合は、
        //ServerサンプルのLocal IP を指定している処で、
         // IP-V4 形式のIPアドレスが取得出来て居ない可能性があります。
    }
    ```
    Server サンプル
    http://homepage2.nifty.com/nonnon/SoftSample/CS.NET/SampleTcpIpSvr.html
    ```C#
    IPAddress myIp = Dns.GetHostEntry("localhost").AddressList[0];
    // ↑で、IP-V4 アドレスが取得出来て居ない可能性があります。
    ↓下記の様に書換てみてください。
    IPAddress myIp = IPAddress.Any;
    ```
    IPAddress myIp に、設定可能なパラメータ例
    myIp = IPAddress.IPv6Any;
    myIp = IPAddress.Any;
    myIp = IPAddress.Parse("192.168.1.12");
     //自PCのIPアドレス192.168.1.12の場合

    USB-COM / TCP / UDP を使う上で避けて通れない機能に、
    delegate があります。様々なサイトで説明が見つかると思います。
    デリゲート
    http://ufcpp.net/study/csharp/sp_delegate.html

    キャンセル

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

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

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

  • C#

    9682questions

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