简单的字符串消息传递客户端/服

时间:2012-07-25 19:54:06

标签: c# multithreading tcp

我正在寻找一种在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# client-server protocol/model question

1 个答案:

答案 0 :(得分: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个头字节,表示以字节为单位的总消息大小
  • 构成消息字符串的任意数量的字节

使用此协议,我们知道所有消息的长度至少为两个字节(理论上最小的有效消息为00 02,表示空字符串)。我们也知道消息的前两个字节告诉我们消息的总大小,所以我们知道何时停止读取数据。

因此,要从上面的代码实现ContainsCompleteMessage()方法,我们需要:

  • 确保数据缓冲区中至少包含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. 
}

我在此描述的协议将满足您在网络上发送短字符串的需求。通用它可以让你发送更复杂的对象;您只需添加指定消息布局的其他元数据。我把它作为读者的练习。