Search code examples
c#streamlisinterfacingastm

How to reset a stream?


I am trying to connect a pathology analyzer and receive data. Following is my code.

private void ReceiveData(string IP, string PortNo)
        {
            var port = Convert.ToInt32(PortNo);
            IPAddress localAddr = IPAddress.Parse(IP);
            server = new TcpListener(localAddr, port);
            byte ACK = 6;
            byte[] ACK_BUFF = { ACK };
            try
            {
                server.Start();
                var bytes = new byte[1024];
                string data = string.Empty;
                TcpClient client = server.AcceptTcpClient();
                using (Stream stream = client.GetStream())
                {
                    while (true)
                    {
                        int i;
                        i = stream.Read(bytes, 0, bytes.Length);
                        if (i > 0)
                        {
                            if (chkBidirectional_NI.Checked)
                                stream.Write(ACK_BUFF, 0, ACK_BUFF.Length);
                            string line = Encoding.UTF8.GetString(bytes, 0, i);
                            if (i > 1)
                            {
                                data += line;
                               
                            }
                            if (data.IndexOf("L|1|N") > -1)
                                ReceiveDataSJH(data);
                        }                                               
                    }                    
                }
            }
            catch (SocketException e)
            {
                MessageBox.Show(e.Message);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }
 private void button1_Click(object sender, EventArgs e)
        {
            Thread thrNoti = new Thread(() => ReceiveData(txtIPAddress___.Text, txtPortNo___.Text));
            thrNoti.Start();
            
        }

Above code is working fine but each time I have to start the program again because stream disposes.
How can I reset my program so it ready again to receive data ?
Update:- Maybe my question is wrong. The main issue is my program stops working after one transfer.
Update2:- I went through this thread. But it's about handling multiple connections at the same time. According to the answer of that thread when I am putting using (Stream stream = client.GetStream()) inside while loop analyzer says LIS is not responding.

Maybe I'm wrong but I think when machine stops sending data stream object disposes because it's by using. So my program stops receiving data after some time.

Please suggest me where am I doing wrong?


Solution

  • You have a while loop here, so you're on the right track; however, you should treat i <= 0 as an EOF condition and exit rather than keep looping forever; Stream.Read returning a non-positive value means EOF (with a slight caveat around zero-length reads, but you're not doing a zero-length read, so don't worry about that).

    The next thing we need to think about is text encoding; I don't know the protocol details of this API, but your line = logic isn't actually valid for UTF8, because you could have bytes from the same character split over multiple reads - necessitating more complex read logic. If the data is actually ASCII then it is much simpler, and that logic is valid. Streams are not message based, so usually you should have some kind of "framing" logic before you try parsing any data; this could be "keep buffering bytes until we see a CR+LF". If you post details (or a link) of the expected protocol, I may be able to help more (stream protocol parsing is something I do a lot).

    There's also what looks like a bug where if the data trickles in one byte at a time, you drop line on the floor each time without ever handling any of it. Again this would be fixed by appropriate "framing" and buffering until an entire frame can be processed. I should emphasize: you might find zero, one or multiple complete frames plus maybe an incomplete frame after any read operation - depending on how the network transmits the incoming data.

    But it looks like you're not far off here, assuming this is actually a multi-message streaming protocol. It doesn't make sense to reset/rewind this kind of stream: you simply can't - you get one shot at handling the data, and then it is gone forever (hence you need to handle any backlog buffering if you can't process an entire frame yet).

    Note that for many simple text-based protocols, you might be able to subcontract all the thinking to StreamReader, and just use ReadLine() until it returns null (which signifies EOF). However, this should be done with some caution, as StreamReader cannot enforce quotas for you to protect against malign payloads (for example, feeding you a constant stream of text without any line breaks). This is probably more of a concern if you're the server than the client.