C#TCPClient流问题

时间:2016-06-13 07:18:38

标签: c# networking tcpclient

我有一个客户端和服务器,都有接收和发送方法,两者都使用相同的类来处理数据包,数据包的标头大小和反序列化等。

如果我发送更小的纯文本消息包,一切都有效,但是当我尝试发送图像时,缓冲区溢出并且出现内存不足异常。 奇怪的是它实际上从数据包的头部找到了正确的数据包大小,但是当它进入簧片时,数据包大小已经变为奇数。 图像是包类内部的字节数组。

在即将读取实际数据包的部分中,PacketLength已更改为非常大的数字或甚至是负数值。 我试图理解为什么它不断变化,尽管不再寻找标题大小..

我确保服务器只发送一个包,我也在发送之前打印包大小,然后检查客户端是否正在接收所述包。 客户保持接收的数量超过预期。

请帮帮我:)。

服务器在发送过程中打印出来的内容:

  • 标题:4
  • Packetsize:123
  • 发送1/1包(127字节)

客户在接收期间打印出来的内容:

  • 收到的数据包,从标题中找到大小:123
  • 开始阅读数据包

(然后一旦读取整个数据包,它就被添加到列表中并转发到其他内部方法,以根据其类型(图像,文本等)处理数据包

将图像嵌入数据包的示例:

  • 服务器说:packetsize是300504 + 4字节标题
  • 服务器发送:1/1包(300508bytes)
  • 客户端说:已收到大小为300504的数据包
  • 然后立即说:
  • 收到尺寸为966440806的太大小包
  • (内存不足)

服务器代码:

    // This is a threaded TCPclient handler on the server.
    private void _TCP_ManageClient(object clientObj)
    {
        uint clientID = _ClientConnected();
        var client = (TcpClient) clientObj;
        bool connected = true;

        _AddClientFromList(ref client, clientID);
        NetworkStream stream = client.GetStream();

        AddPacketToSend(_Packet_Welcome(clientID)); // Welcome, client #X. message is sent out.

        while (connected) 
        {
            // S E N D     P A C K E T
            SendPacketsInQueue(stream);

            if (stream.DataAvailable)
            {
                // R E C E I V E     P A C K E T
                ReceivePacketsFromStream(stream);

                // R E A D      P A C K E T
                ReadPacketsInQueue(ref connected);
            }
        }
        if (!connected) { Con.Add(m_Logtag, "Client[" + clientID + "] dropped"); }
    }

    // Send packets which are in the format of 'RemuseNetPacket' class.
    public void SendPacketsInQueue(NetworkStream stream)
    {
        if (m_SendMessageList.Count > 0)
        {
            byte[] packetBytes;
            byte[] readyData;
            int byteCount = 0;
            int sentPackets = 0;
            for (int i = 0; i < m_SendMessageList.Count; i++)
            {
                packetBytes = m_SendMessageList[i].Serialize();
                Int32 headersize = packetBytes.Length;
                byte[] packetLength = BitConverter.GetBytes(headersize);
                Con.Add(m_Logtag, "Header size: " + headersize);
                Con.Add(m_Logtag, "PacketLength: " + packetLength.Length);
                readyData = Extensions.Concatenate(packetLength, packetBytes);
                stream.Write(readyData, 0, readyData.Length);
                byteCount += readyData.Length;
                sentPackets++;
            }
            Con.Add(m_Logtag, "Sent " + sentPackets + "/" + m_SendMessageList.Count + " packets (" + byteCount + " bytes)");
            int r = m_SendMessageList.Count;
            m_SendMessageList.Clear();
            Con.Add(m_Logtag, "Removed " + r + " sent packages from list");
        }
    }

客户代码:

// This is the client's TCP loop.
        private void _TCPClientStart()
        {
            try
            {
                TCPClient = new TcpClient();
                TCPClient.Connect(m_HostIP, m_Port);
                Con.Add(m_Logtag, "Connected to " + m_HostIP + ":" + m_Port);
                m_IsRunning = true;
                m_Connected = true;
                NetworkStream stream = TCPClient.GetStream();

                AddPacketToSend(_Packet_Hello()); // Hello, I am [computer name]. message is sent out.

                while (m_Connected)
                {
                    if (stream.DataAvailable)
                    {
                        // R E C E I V E     P A C K E T
                        ReceivePacketsFromStream(stream);

                        // R E A D      P A C K E T
                        ReadPacketsInQueue();
                    }
                    // S E N D      P A C K E T
                    SendPacketsInQueue(stream);
                }
                Disconnect();
            }
            catch (Exception e)
            {
                Con.Add(m_Logtag, "TCPclient Exception: " + e.ToString());
                Con.Add(m_Logtag, "Stacktrace: " + e.StackTrace);
            }
        }

        // Client receives a packet.
        private void ReceivePacketsFromStream(NetworkStream stream)
        {
            int PacketLength = -1;
            int BytesRead = 0;
            byte[] ReceivedBytes = new byte[0];

            while (stream != null && stream.DataAvailable)
            {
                // Read packet's header (first 4 bytes)
                if (PacketLength < 0)
                {
                    if (BytesRead == 0) { ReceivedBytes = new byte[m_HeaderLength]; }

                    BytesRead += stream.Read(ReceivedBytes, BytesRead, (ReceivedBytes.Length - BytesRead));

                    if (BytesRead == m_HeaderLength)
                    {
                        PacketLength = BitConverter.ToInt32(ReceivedBytes, 0);

                        // Obtained information about the packet's size.
                        if (PacketLength < m_MaxPacketSize)
                        {
                            Con.Add(m_Logtag, "Received packet header, packet size: " + PacketLength);
                            BytesRead = 0;
                            Array.Clear(ReceivedBytes, 0, ReceivedBytes.Length);
                        }
                        else
                        {
                            Con.Add(m_Logtag, "Received too big packet: " + PacketLength);
                        }
                    }
                }
                // Start reading packet content.
                else
                {
                    Con.Add(m_Logtag, "Start reading packet");

                    if (BytesRead == 0) { ReceivedBytes = new byte[PacketLength]; }
                    BytesRead += stream.Read(ReceivedBytes, BytesRead, (ReceivedBytes.Length - BytesRead));

                    // Whole packet obtained.
                    if (BytesRead >= PacketLength)
                    {
                        RemuseNetPacket packet = new RemuseNetPacket();
                        packet = packet.Desserialize(ReceivedBytes);
                        Con.Add(m_Logtag, "Received packet #" + packet.ID);

                        // Add packet to list for reading.
                        if (packet != null) { AddPacketToRead(packet); }
                        BytesRead = 0;
                        PacketLength = -1;
                        Array.Clear(ReceivedBytes, 0, ReceivedBytes.Length);
                    }
                }

            }
        }

编辑:添加图片包类型代码

    private RemuseNetPacket _Packet_Screen()
    {
        Con.Add(m_Logtag, "Send Image packet");
        RemuseNetPacket p = new RemuseNetPacket();
        p.Type = RemusePacketType.Image;

// captures the screen with the mouse (true) using format jpeg.
        p.Data = ScreenCapture.CaptureToBytes(true, m_ImageFormat);
        Con.Add(m_Logtag, "package img size: " + p.Data.Length);
        p.SenderName = m_Name;
        p.Timestamp = _GetCurrentTimestamp();
        return p;
    }

这是日志中关于奇怪数据包大小的内容:

[Active] Host:  Send Image packet (this is where i sent 1 image packet)
[Active] Host:  removed 1 sent packages from list
[Active] Client:  Start reading packet
[Active] Client:  Received data: 74456 / 327332 (this is the actual packet size)
[Active] Client:  Received packet header, packet size: -251848753 (suddenly it becomes this..)
[Active] Client:  Start reading packet
[Active] Client:  Received data: 4 / 1251185707
[Active] Client:  Received data: 4 / 1251185707
[Active] Client:  Received data: 4 / 1251185707
[Active] Client:  Received data: 4 / 1251185707
[Active] Client:  Received data: 4 / 1251185707
[Active] Client:  Received data: 4 / 1251185707

1 个答案:

答案 0 :(得分:2)

难以具体诊断,但这是这种情况下更典型的读取循环;更简单,可能更容易调试:

byte[] buffer = new byte[512];
while(true) {
    if(!Fill(stream, buffer, 4)) break;
    int len = BitConverter.ToInt32(buffer, 0);
    if(buffer.Length < len) buffer = new byte[len]; // need moar!
    if(!Fill(stream, buffer, len)) throw new EndOfStreamException();
    ProcessData(buffer, len); // note: only look at the first "len" bytes
}

static bool Fill(Stream source, byte[] destination, int count) {
    int bytesRead, offset = 0;
    while(count > 0 &&
        (bytesRead = source.Read(destination, offset, count)) > 0)
    {
        offset += bytesRead;
        count -= bytesRead;
    }
    return count == 0;
}