C#Tcp正在丢失数据包?

时间:2014-02-24 21:53:45

标签: c# sockets tcp chat

我写了一个C#聊天软件,它使用了一个我称之为请求系统的新系统(至少对我而言)。我不知道之前是否已创建过,但现在我认为它是我的创作:P

无论如何,这个系统的工作原理如下:

  1. soc收到信号
  2. 检查信号
  3. 如果刚刚收到的数据是数字2,则客户端软件知道服务器即将发送聊天消息。如果数字是3,那么客户端知道服务器即将发送成员列表,依此类推。
  4. 问题是这样的:当我在VS2012中一步一步地工作时它工作正常,聊天工作正常。当我在调试模式下使用它或者只是在我的桌面上运行它时,似乎缺少数据,它不应该是因为代码工作得很好......

    客户端上发送和接收消息的代码示例:

        public void RecieveSystem()
        {
            while (true)
            {
                byte[] req = new byte[1];
                soc.Receive(req);
                int requestID = int.Parse(Encoding.UTF8.GetString(req));
                if (requestID == 3)
                {
                    byte[] textSize = new byte[5];
                    soc.Receive(textSize);
                    byte[] text = new byte[int.Parse(Encoding.UTF8.GetString(textSize))];
                    soc.Receive(text);
                    Dispatcher.Invoke(() => { ChatBox.Text += Encoding.UTF8.GetString(text) + "\r\n"; });
                }
            }
        }
    
        public void OutSystem(string inputText)
        {
            byte[] req = Encoding.UTF8.GetBytes("3");
            soc.Send(req);
            byte[] textSize = Encoding.UTF8.GetBytes(Encoding.UTF8.GetByteCount(inputText).ToString());
            soc.Send(textSize);
            byte[] text = Encoding.UTF8.GetBytes(inputText);
            soc.Send(text);
            Thread.CurrentThread.Abort();
        }
    

    并在服务器上:

        public void UpdateChat(string text)
        {
            byte[] req = Encoding.UTF8.GetBytes("3");
            foreach (User user in onlineUsers)
                user.UserSocket.Send(req);
            byte[] textSize = Encoding.UTF8.GetBytes(Encoding.UTF8.GetByteCount(text).ToString());
            foreach (User user in onlineUsers)
                user.UserSocket.Send(textSize);
            byte[] data = Encoding.UTF8.GetBytes(text);
            foreach (User user in onlineUsers)
                user.UserSocket.Send(data);
        }
               public void RequestSystem(Socket soc)
            {
    ~~~
                        }
                        else if (request == 3)
                        {
                            byte[] dataSize = new byte[5];
                            soc.Receive(dataSize);
                            byte[] data = new byte[int.Parse(Encoding.UTF8.GetString(dataSize))];
                            soc.Receive(data);
                            UpdateChat(Encoding.UTF8.GetString(data));
                        }
                    }
                    catch
                    {
                        if (!soc.Connected)
                        {
                            Dispatcher.Invoke(() => { OnlineMembers.Items.Remove(decodedName + " - " + soc.RemoteEndPoint); Status.Text += soc.RemoteEndPoint + " Has disconnected"; });
                            onlineUsers.Remove(user);
                            Thread.CurrentThread.Abort();
                        }
                    }
                }
            }
    

    可能是什么问题?

1 个答案:

答案 0 :(得分:4)

您假设每个Send电话都有一个数据包。这不是面向流的 - 这是面向数据包的。您发送的多个数据我怀疑是合并到一个数据包中,然后您将在一次Receive调用中获取所有这些数据。 (即使涉及多个数据包,单个Receive呼叫仍然可以接收所有数据。)

如果您正在使用TCP / IP,那么您应该考虑采用更加面向流的方式。我也鼓励你改变协议的设计,这至少可以说是奇怪的。在每条消息之前使用长度前缀是很好的,但是当你在两台计算机之间有完美的二进制连接时,为什么要将它编码为文本呢?

我建议您查看BinaryReaderBinaryWriter:使用TcpClientTcpListener而不是Socket(或至少使用NetworkStream) ,并使用读/写器对使其更容易读取和写入数据(有效载荷或基元,如消息的长度)。 (BinaryWriter.Write(string)甚至为您执行长度前缀,这使事情变得更容易。)