C# 从TcpClient的流中读取所有数据

C# 从TcpClient的流中读取所有数据,c#,stream,tcpclient,C#,Stream,Tcpclient,我在我的工厂里用一台新机器工作,这台机器是通过PC控制的。电流卡在通过以太网连接的摄像系统上 这是我打开连接的代码 TcpClient client; NetworkStream stream; public bool OpenConnection() { client = new TcpClient(); try { //Camera.Open(); client.Connect("192.168.0.10", 8500); strea

我在我的工厂里用一台新机器工作,这台机器是通过PC控制的。电流卡在通过以太网连接的摄像系统上

这是我打开连接的代码

TcpClient client;
NetworkStream stream;

public bool OpenConnection()
{
   client = new TcpClient();

   try
   {
      //Camera.Open();
      client.Connect("192.168.0.10", 8500);
      stream = client.GetStream();

   }
   catch (Exception ex)
   {
       return false;
   }
    return true;
 }
到目前为止还不错。一旦连接打开,我就会向摄像机索取一些信息 我使用的消息格式有STX(0x02)来表示消息的开始,ETX(0x03)作为消息的结束

    char StartOfPacket = (char)0x02;
    char EndOfPacket= (char)0x03;

    public bool RetrieveDigits(out string Digits)
    {
        // Send the trigger cammand to the vision system
        Digits = "";
        bool EverythingOK = true;
        string DataToSend = StartOfPacket + "T1" + EndOfPacket;
        byte[] buff = Encoding.ASCII.GetBytes(DataToSend);

        if (LogCameraEvent != null)
            LogCameraEvent(">> " + DataToSend);

        try
        {
            stream.Write(buff, 0, buff.Length);
        }
        catch (Exception ex)
        {
            Logging.Instance.LogExceptionToFile(MethodBase.GetCurrentMethod(), ex);
            EverythingOK = false;
        }

        Thread.Sleep(100);

        byte[] buffer;

        if (EverythingOK)
        {
            // Check the response
            buffer = ReadCamera(10);

            // Process the packets
            string[] packets = ProcessPackets(buffer);

            if (packets != null)
            {
                if (packets.Length > 0)
                {
                    bool TriggerFound = false;

                    for (int i = 0; i < packets.Length; i++)                            
                        {
                            if (packets[i] == "T1")
                            {
                                TriggerFound = true;
                                continue;
                            }
                            else if (TriggerFound)
                            {
                                // If we are here then we should now be the data that was requested
                                if (string.IsNullOrEmpty(packets[i]))
                                {
                                        Digits = packets[i-1];  // previous packet may have data from previous trigger. Need to look into why this happens.
                                }
                                else
                                    Digits = packets[i];
                                EverythingOK = true;
                                break;
                            }
                            else
                                EverythingOK = false;
                        }
                }
                else
                {
                    Console.WriteLine("No Packets Recieved");
                    EverythingOK = false;
                }
            }
            else
            {
                Console.WriteLine("No Packets Recieved");
                EverythingOK = false;
            }
        }

        return EverythingOK;
    }
所以我看到了摄像机发出的信息。我确认电脑已使用wire shark接收到数据。 现在在
RetrieveDigits
方法中,您可以看到我处理接收到的数据包,循环遍历数据包直到找到“T1”,然后假设下一个数据包就是我要查找的数据,并将
数字设置为该值。
我发现,有时当我运行应用程序时,我会看到
Digits
被设置为“”。 我还发现,有时我收到的数据将是“AA”然后是“T1”,而不是“T1”然后是“AA”。我怀疑的是,当它从后到前的时候,“AA”实际上是来自于之前从摄像机发送的数据,并且由于某种原因,它在从流中读取时被遗漏了

在我读取数据流之前,任何关于为什么会发生这种情况的想法都是错误的

编辑: 修改了
ReadCamera
代码以处理数据包,每次读取1个字节

private string[] ReadCamera(int ExpectedLength, int ExpectedPackets)
    {
        List<string> Packets = new List<string>();            
        bool StartFound = false;            

        StringBuilder sb = new StringBuilder();

        if(ExpectedLength < 1)
        {
            ExpectedLength = 100;
        }

        byte[] Buffer = new byte[ExpectedLength];
        int read = 0;

        while (true)
        {
            read += stream.Read(Buffer, read, 1);

            // Check to see if the byte read is the start of a packet
            if (Buffer[read - 1] == StartOfPacket)
            {
                StartFound = true;
            }
            else if (StartFound)
            {
                // Check to see if the byte read is the end of a packet
                if (Buffer[read - 1] == EndOfPacket)
                {
                    Packets.Add(sb.ToString());
                    sb.Clear();
                    StartFound = false;

                    if (Packets.Count == ExpectedPackets)
                        break;
                }
                else
                {
                    sb.Append(Encoding.ASCII.GetChars(Buffer, read - 1, 1));
                }
            }
        }            

        // For Debuggin purposes
        foreach(string s in Packets)
            if (LogCameraEvent != null)
                LogCameraEvent("<< " + s);

        return Packets.ToArray();
    }

虽然我怀疑这是否相关,但我建议使用
使用
块和
client=new TcpClient()
stream=client.GetStream()因为它们实现IDisposable.DataAvailable几乎总是一个错误。它不会做你认为它会做的事。完全从代码中删除它。@BradM感谢您的评论,通常我会这样做并建议这样做,但在我的应用程序中,我会轮询相机系统,所以当不再需要时,我会手动关闭流。@usr感谢您提供的信息,您知道另一种方法吗?根本无法判断另一方何时完成发送,因为它随时可能发送另一个字节。您可以一直读取,直到获得零字节(流结束),或者直到您可以从读取的字节中检测到消息已完成。
>>[STX]T1[ETX]
<<[STX]T1[ETX][STX]AA[ETX] 
private string[] ReadCamera(int ExpectedLength, int ExpectedPackets)
    {
        List<string> Packets = new List<string>();            
        bool StartFound = false;            

        StringBuilder sb = new StringBuilder();

        if(ExpectedLength < 1)
        {
            ExpectedLength = 100;
        }

        byte[] Buffer = new byte[ExpectedLength];
        int read = 0;

        while (true)
        {
            read += stream.Read(Buffer, read, 1);

            // Check to see if the byte read is the start of a packet
            if (Buffer[read - 1] == StartOfPacket)
            {
                StartFound = true;
            }
            else if (StartFound)
            {
                // Check to see if the byte read is the end of a packet
                if (Buffer[read - 1] == EndOfPacket)
                {
                    Packets.Add(sb.ToString());
                    sb.Clear();
                    StartFound = false;

                    if (Packets.Count == ExpectedPackets)
                        break;
                }
                else
                {
                    sb.Append(Encoding.ASCII.GetChars(Buffer, read - 1, 1));
                }
            }
        }            

        // For Debuggin purposes
        foreach(string s in Packets)
            if (LogCameraEvent != null)
                LogCameraEvent("<< " + s);

        return Packets.ToArray();
    }
// Check the response
string[] packets = ReadCamera(10,2);

// Process the packets
//string[] packets = ProcessPackets(buffer);