首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C# Tcp正在丢失数据包吗?

C# Tcp正在丢失数据包吗?
EN

Stack Overflow用户
提问于 2014-02-24 21:53:45
回答 1查看 2.8K关注 0票数 0

我编写了一个C#聊天软件,它使用了一个新的(至少对我来说)系统,我称之为请求系统。我不知道它以前是否被创造过,但现在我认为它是我的创造。

无论如何,这个系统是这样工作的:

  1. soc接收信号
  2. 检查信号
  3. 如果它刚刚收到的数据是数字2,客户端软件知道服务器即将发送一条聊天消息。如果编号为3,那么客户机就知道服务器即将发送成员列表,依此类推。

问题是:当我一步一步地在VS2012中工作的时候,聊天就正常了。当我在调试模式下使用它或者只是在我的桌面上运行它时,似乎缺少数据,这不应该是因为代码工作得很好.

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

代码语言:javascript
复制
    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();
    }

在服务器上:

代码语言:javascript
复制
    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();
                    }
                }
            }
        }

有什么问题吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-02-24 21:57:28

您假设每个Send呼叫都有一个数据包。那不是面向流的-是面向数据包的。您正在发送多个数据片段,我怀疑这些数据被合并成一个包,然后在一个Receive调用中将它们全部获取。(即使涉及多个数据包,一个Receive调用仍然可以接收所有数据。)

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

我建议您查看BinaryReaderBinaryWriter:使用TcpClientTcpListener而不是Socket (或至少使用NetworkStream),并使用读取器/写入器对来简化数据的读取和写入(无论是有效负载还是消息长度等原语)。(BinaryWriter.Write(string)甚至为您执行长度前缀,这使事情变得更简单。)

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21999861

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档