C# 从套接字读取错误的数据

标签 c# arrays sockets bit-manipulation

我正在尝试通过一个套接字将随机单词发送到另一个套接字。 我为数据管理设计了一个简单的协议(protocol),每个数据包都包含实际消息长度的前 4 个字节(以字节为单位),然后是消息本身。

这是客户端代码:

    private byte[] sendBuffer = new byte[1000];
    private Socket sSocket;
    private void WriteDataLength(int length)
    {
        sendBuffer[0] = (byte)(length);
        sendBuffer[1] = (byte)(length >> 8);
        sendBuffer[2] = (byte)(length >> 16);
        sendBuffer[3] = (byte)(length >> 24);
    }
    private void DoWork()
    {
        while (true)
        {
            string word = RandomString(random.Next(1, 10)); //generates a random string.
            byte[] toBytes = Encoding.ASCII.GetBytes(word); //converting the string to byte array.
            int length = toBytes.Length; // length of the actual data(the word length).
            WriteDataLength(length);//writing the word length in bytes.
            Buffer.BlockCopy(toBytes, 0, sendBuffer, 4, toBytes.Length);//copying the array which hold the word to the sendBuffer (start from the 4th byte).
            sSocket.Send(sendBuffer, length+4 , SocketFlags.None);//send +4 bytes for the length prefix.        
        }
    }
    private static Random random = new Random();         
    public static string RandomString(int length)
    {
        const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        return new string(Enumerable.Repeat(chars, length)
          .Select(s => s[random.Next(s.Length)]).ToArray());
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        TcpClient tcpClient = new TcpClient();
        tcpClient.Connect("localhost", 10);
        sSocket = tcpClient.Client;
        Thread th = new Thread(DoWork);
        th.Start();
    }

如你所见,我生成了一个随机词,写入它的前 4 个字节(简单地移动位),然后将其复制到 sendBuffer。

服务器代码:

    private byte[] recieveBuffer = new byte[1000];
    TcpListener tListener;
    Socket rSocket;
    private int readData()
    {
        rSocket.Receive(recieveBuffer, 0, 4, SocketFlags.None); //read the first 4 bytes
        int size = getDatalength(); //reassemble the bytes to the original value.
        int dataleft = size;
        int totalread = 4; //read already 4 bytes.
        int recv;
        while (totalread < size)
        {
            recv = rSocket.Receive(recieveBuffer, totalread, dataleft, 0);
            if (recv == 0) //stop reading
            {
                break;
            }
            totalread += recv;
            dataleft -= recv;
        }
        return size;
    }


    private int getDatalength()
    {
        int length = recieveBuffer[0] | recieveBuffer[1] << 8 | recieveBuffer[2] << 16 | recieveBuffer[3] << 24;
        return length;
    }
    private void DoWork()
    {
        while (true)
        {
            int length = readData();
            byte[] word = new byte[length]; //initializing a new array to hold the word
            Buffer.BlockCopy(recieveBuffer, 4, word, 0, length); //copying to the recieveBuffer from the 4th place( first 4 bytes are always length header).
            string result = Encoding.ASCII.GetString(word);
            Console.WriteLine(result);
        }
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        tListener = new TcpListener(IPAddress.Any, 10);
        tListener.Start();
        rSocket = tListener.AcceptTcpClient().Client;
        Thread th = new Thread(DoWork);
        th.Start();

    }

在服务器端,我读取前 4 个字节以获得长度(这样我就可以知道我必须读取多少),然后我开始循环直到数据大小结束。

我实际上不知道如何解释这个,它工作了 2 或 3 秒,然后 Server 抛出一个 System.ArgumentOutOfRangeException 预期在这一行中:

recv = rSocket.Receive(recieveBuffer, totalread, dataleft, 0);

我对此进行了调试,发现 size 变量包含非常大的数字...(例如几百万),所以我猜问题出在读取前 4 个字节...

我还尝试输出 recieveBuffer 的前 4 个值,它们与客户端的值不同..(当抛出异常时,它们是相同的)。

我不确定这里出了什么问题..我会很感激你的帮助。

谢谢。

最佳答案

…你的计算有一个错误:当你比较 totalread < size 时,size 不包括消息长度的 4 个字节,但你已经将它们添加到 totalread,所以你应该从 0 开始 totalread 忽略长度的 4 个字节,或者您的编写代码应将它们添加到总长度中。 – o_weisman

关于C# 从套接字读取错误的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41411573/

相关文章:

c# - 替换 ASP.net MVC 核心中的 DefaultModelBinder

c# - 删除最后 N 条记录, Entity Framework

c# - Silverlight 浏览器外显示白屏

java - Angular 客户端向 Java 服务器发送 POST 请求的参数

arrays - Mongoose 模式需要可以为空的数组

c# - 在 C# 中实现套接字监听器的最佳方式

c# - C#异步Socket.BeginSendFile仅发送两个异步文件

c# - 缺少模型/IdentityModel.cs

c# - 为什么我在本地声明的变量在 finally block 中没有被识别?

javascript - 将数组扁平化为一个对象,同时减少一个属性