1

単純な文字列メッセージを送受信するために TCP でプロトコルを実装する方法を探しています。クライアントとサーバーアプリがあり、両方が初めて実行を開始するときに、クライアントの接続ボタンを押してサーバーに接続します。クライアントが接続されたことを示すテキストがサーバーのリストボックスに表示され、クライアントのリストボックスにサーバーに接続されたことを示すテキストが表示されます。

その部分は問題なく動作しますが、他の文字列をサーバーに送信できるようにしたいのですが、送信した文字列に応じて、サーバーに特定の操作を実行させるにはどうすればよいですか? 頭に浮かぶ最初のアイデアは、if-then ステートメントをどこかで使用することです。以下にコードを投稿します。

サーバ:

    private static int port = 8080;
    private static TcpListener listener;
    private static Thread thread;


   private void Form1_Load(object sender, EventArgs e)
    {

        listener = new TcpListener(new IPAddress(new byte[] { 10, 1, 6, 130 }), port);
        thread = new Thread(new ThreadStart(Listen));
        thread.Start(); 


    }

   private void Listen()
    {
        listener.Start();
        listBox1.Invoke(new EventHandler(delegate { listBox1.Items.Add("Listening on: " + port.ToString()); }));


        while (true)
        {              
            listBox1.Invoke(new EventHandler(delegate { listBox1.Items.Add("Waiting for connection...."); }));
            TcpClient client = listener.AcceptTcpClient();
            Thread listenThread = new Thread(new ParameterizedThreadStart(ListenThread));
            listenThread.Start(client);

        }
    }

    //client thread 
    private void ListenThread(Object client)
    {

        NetworkStream netstream = ((TcpClient)client).GetStream();

        listBox1.Invoke(new EventHandler(delegate { listBox1.Items.Add("Request made"); }));


        byte[] resMessage = Encoding.ASCII.GetBytes("Connected to Server");



        netstream.Write(resMessage, 0, resMessage.Length);
        netstream.Flush();

    } 

クライアント:

 TcpClient tcpclnt;

 private void buttonConnect_Click(object sender, EventArgs e)
    {
        try
        {
            tcpclnt = new TcpClient();
            userEventBox.Items.Add("Connecting.....");

            try
            {

                tcpclnt.Connect("10.1.6.130", 8080);

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());


                return;
            }

            Stream stm = tcpclnt.GetStream();

            byte[] bb = new byte[100];
            int k = stm.Read(bb, 0, 100);

            string returndata = System.Text.Encoding.ASCII.GetString(bb);

            userEventBox.Items.Add(returndata);
            tabControl1.Enabled = true;


           //need a way for the server see this string
            string populateList = "Test";

            ASCIIEncoding asen = new ASCIIEncoding();

            byte[] ba = asen.GetBytes(populateList);
            stm.Write(ba, 0, ba.Length);              
        }

        catch (Exception ex)
        {
            Console.WriteLine("Error..... " + ex.StackTrace);
        }
    }

私はかなり立ち往生しており、この件に関してあなたが提供できる助けをいただければ幸いです. ありがとうございました。

ソース -> C# クライアント サーバー プロトコル/モデルの質問

4

1 に答える 1

4

接続を確立した後、クライアントとサーバーの両方が、NetworkStream新しいデータがないかオブジェクトを継続的に監視する必要があります。データが受信されると、完全なメッセージを構成するのに十分な量を受信するまで、ある種のデータ バッファーに追加する必要があります。適切な量​​のデータを受信したら、そこからメッセージを解析して適切に応答することができます。

基本的に、次のようなロジックを設定する必要があります。

var data = new byte[1024];
var dataLength = 0;
var dataBuffer = new MyCustomDataBuffer();
while (true)
{
    while (stream.DataAvailable)
    {
        dataLength = stream.Read(data, 0, data.Length);
        dataBuffer.Append(data, dataLength);
        while (dataBuffer.ContainsCompleteMessage())
        {
            dataBuffer.ProcessMessage();
        }
    }
}

この例の制御フローは大幅に単純化されていますが、アイデアは理解できるはずです。の実装も提供しませんがMyCustomDataBuffer、そのようなクラスを書くことはそれほど複雑ではありません。実際には、バイトのストリームだけです。

完全なメッセージを受信したかどうかはどうすればわかりますか? まあ、それがプロトコルの要点です: これらのことを知ることを可能にするルールを確立することです. 各メッセージが同じ 2 つの部分で構成されるデータ プロトコルの簡単な例を考えてみましょう。

  • 合計メッセージ サイズをバイト単位で表す 2 ヘッダー バイト
  • メッセージ文字列を構成する任意のバイト数

このプロトコルでは、すべてのメッセージが少なくとも 2 バイトの長さであることがわかっています (理論上の最小の有効なメッセージは00 02で、これは空の文字列を表します)。また、メッセージの最初の 2 バイトがメッセージの合計サイズを示していることもわかっているため、データの読み取りをいつ停止するかがわかります。

したがって、ContainsCompleteMessage()上記のコードのメソッドを実装するには、次のことを行う必要があります。

  • データ バッファーに少なくとも 2 バイトあることを確認してください。
  • これらの 2 バイトを整数に変換します。
  • そして、データ バッファーに少なくともそのバイト数があるかどうかを判断します。

有効なメッセージがあることがわかったら (そしてメッセージの大きさがわかれば)、データ バッファーから最初の N バイト (N はメッセージのサイズ) を切り取ってから、メッセージ文字列を取り出します。メッセージ データの関連するセグメントから:

// here, 'msg' is a byte array that contains just the message data
var msgString = Encoding.UTF8.GetString(msg, 2, msg.Length - 2);
switch (msgString)
{
    case "kill": KillServer(); break;
    // etc. 
}

ここで説明するプロトコルは、ネットワークを介して短い文字列を送信する必要性を満たします。一般化すると、より複雑なオブジェクトを送信できます。メッセージのレイアウトを指定するメタデータを追加するだけです。それは読者の練習問題として残しておきます。

于 2012-07-25T20:43:55.663 に答える