0

i have developed one application which will interact with the plc using TCP server socket program. each cycle plc is sending one signal to my application as character('R').
but some times i am not receiving any character. that means event is not firing. but next time when plc sends 'R', i will receive it as 'RR'. my code is `

private void _tcpServerFortest_OnRead(Socket soc)
    {
      //  rec = new byte[1];
        byte[] rec = _tcpServerFortest.ReceivedBytes;

        string str = System.Text.ASCIIEncoding.ASCII.GetString(rec);`
}

and my code for starting TCP server is

   _tcpServerFortest = new CServerSocket(2005);
                _tcpServerFortest .OnConnect += _tcpServerFortest _OnConnect;
                _tcpServerFortest .OnDisconnect += _tcpServerFortest _OnDisconnect;
               _tcpServerFortest .OnRead += _tcpServerFortest _OnRead;
               _tcpServerFortest .Active();

in my class cServerSocket, data received method is as below

 private void OnDataReceived(IAsyncResult asyn)
    {
        SocketPacket socketData = (SocketPacket)asyn.AsyncState;
        try
        {
            int iRx = socketData.m_currentSocket.EndReceive(asyn);
            if (iRx < 1)
            {
                socketData.m_currentSocket.Close();
                if (!socketData.m_currentSocket.Connected)
                {
                    if (OnDisconnect != null)
                        OnDisconnect(socketData.m_currentSocket);
                    Clients.Remove(socketData.m_currentSocket);
                    socketData.m_currentSocket = null;
                }
            }
            else
            {

                mBytesReceived = socketData.dataBuffer;
                char[] chars = new char[iRx + 1];
                Decoder d = Encoding.UTF8.GetDecoder();
                d.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);
                mTextReceived = new String(chars);
                if (OnRead != null)
                    OnRead(socketData.m_currentSocket);
                WaitForData(socketData.m_currentSocket);
            }
        }
        catch (InvalidOperationException ex)
        {
            if (socketData.m_currentSocket.Connected)
                socketData.m_currentSocket.Close();
            if (!socketData.m_currentSocket.Connected)
            {
                if (OnDisconnect != null)
                    OnDisconnect(socketData.m_currentSocket);
                Clients.Remove(socketData.m_currentSocket);
                socketData.m_currentSocket = null;
            }
            else
                if (OnError != null)
                    OnError(ex.Message, null, 0);
        }
        catch (SocketException se)
        {
            if (OnError != null)
                OnError(se.Message, socketData.m_currentSocket, se.ErrorCode);
            if (!socketData.m_currentSocket.Connected)
            {
                if (OnDisconnect != null)
                    OnDisconnect(socketData.m_currentSocket);
                Clients.Remove(socketData.m_currentSocket);
                socketData.m_currentSocket = null;
            }
        }
    }

can anyone help me out to solve this problem?

1 Answers1

1

TCP works on streams, not messages. It seems you really want to send messages, so UDP might be a better choice.

When you send data on TCP, you're not guaranteed this will result in a single receive on the other side. A single send can result in multiple receives, and multiple sends can be batched into a single receive (as you found out). You're supposed to read data continuously, and interpret it as required by your communication protocol. In your case, this can be as simple as "read a single byte at a time" - but only you know what exactly you want.

Also, I'd recommend not using a communication wrapper based on Delphi; the programming models are different, and it seems the only reason this library was created is to have people familiar with Delphi not learn how things are done in .NET. It's way too low level to be useful, while not really giving you much choice in working with the data.

Regardless of the solution you choose, there's already hundreds of similar questions on Stack Overflow you can take a look at; for example Handling messages on top of TCP. The basic solutions are:

  • Implement some form of message framing. This can be as simple as "each message is one byte long", or "every message is prefixed by 4 bytes indicating length of the message" or "each message ends with a delimiter".
  • Switch over to UDP, which is a message-based protocol. Since it seems you care about current state of the device rather than a single stream of messages, this might be a better option anyway - you get lower latency and messages, in exchange for losing the ordering and reliability. You need to decide if that's a good thing for you.

If you keep TCP, you need to learn how to work with TCP. This means handling graceful shutdown (receive returns 0 bytes), reading data properly (keep calling receive until you get the whole message, keep the rest in a buffer for later, ...), error handling. It means understanding how latency works on TCP (sends aren't always sent right away, unless you explicitly ask them to). It means understanding that the data you receive can be delayed because some message you don't care about needs to be re-transmitted. TCP isn't simple, and the tricky part is that it's easy to make it work most of the time - and then all your assumptions break down.

Luaan
  • 62,244
  • 7
  • 97
  • 116
  • we just want to share single character like R – sudhakar nayak Dec 13 '18 at 13:42
  • @sudhakarnayak TCP doesn't guarantee you that a single send results in a single receive on the other end. In fact, it's *designed* not to, for performance reasons (among other things). TCP is for streams, not messages. It's for reliability, not low latency. If you want to send distinct messages over TCP, you need to write a communication protocol that does that (or use a library) - TCP doesn't. There's many other problems with your code, but this is the fundamental one. – Luaan Dec 13 '18 at 13:48
  • Also make sure you have a terminator on each piece of data like a return so you can spit the data properly. Luaan is getting more complicated than necessary. Simple TCP will work provided the receiver know where the end of each message is located and read to end of each message before proceswsing. Also with TCP you can get receive data with zero bytes when Keep-Alive is used. Use on e of following 1) ASCII data : terminated with character not in data. 2) ASCII or Binary : preceded each message with byte count. 3) ASCII or Binary : Use fixed length messages. – jdweng Dec 13 '18 at 14:08
  • @jdweng Why bother putting that as comment on my question? Just write an answer ;) Comments aren't for writing answers. In any case "know where the end of each message is located" **is** a communication protocol. UDP fits the OP's stated problem better, and is easier to use in that particular circumstance. Whether a custom protocol on top of TCP is a better choice than UDP is something that the OP needs to decide. – Luaan Dec 13 '18 at 14:13
  • @Luaan : As I said you are making the request much more complicated than necessary. It is equivalent to saying a CSV file is a protocol. CSV files can be generated and read with one instructions per line. Yes CSV is a protocol but nobody calls it a protocol because it is so simple. – jdweng Dec 13 '18 at 14:28
  • @jdweng CSV is not a protocol, it's (barely) a file format. *Make your own answer*. – Luaan Dec 13 '18 at 15:57
  • @Luaan : Get your terminology correct. A protocol is application software so writes at application layer can be consider a protocol. Wiki says "a protocol is a common means for unrelated objects to communicate with each other" – jdweng Dec 13 '18 at 16:54
  • @jdweng Please learn the protocol for Stack Overflow. – Luaan Dec 13 '18 at 18:11
  • @Luaan What you do not understand is that you can have very simple protocols. Your insisting that protocols must be complicated. I'm saying that there are lots of protocols that are very simple like text files/transfers where every line is terminated with a return. – jdweng Dec 13 '18 at 18:51
  • @jdweng I never said anything about protocols being complicated. Don't put words in my mouth. In fact, I suggested using UDP which is far simpler than any protocol on top of TCP. To write any protocol on top of TCP, you need to understand TCP - and it's obvious from the plethora of questions on Stack Overflow that TCP *isn't* as simple as people think. I even have a few simple samples of how to use TCP on C# 5 on GitHub, because it comes up so often. It's easy to do TCP wrong, and even most tutorials do just that. – Luaan Dec 14 '18 at 08:44