How to establish communication between client and server?


Warning: count(): Parameter must be an array or an object that implements Countable in /home/styllloz/public_html/qa-theme/donut-theme/qa-donut-layer.php on line 274
0 like 0 dislike
9 views
Between the server and the client is communicating via the class communicators.
Basic Communicator
public abstract class TcpCommunicatorBase : ICommunicator { private readonly byte[] _bufer = new byte[1024]; protected TcpClient _client; protected Encoding _encoding; private object _streamLock; private object _clientLock; /// /// Variable is needed to stop listening /// private bool _stopListen; protected int? expectedMessageLenght; protected string Message = string.Empty; protected TcpCommunicatorBase(TcpClient client, Encoding encoding) { _streamLock = new object(); _clientLock = new object(); lock (_clientLock) { _encoding = encoding; _client = client; MessageReaded = (s, a) => { }; ConnectionBroken = (s, a) => { _client.Close(); EndListenForMessage(); }; } } /// /// Get the stream /// protected NetworkStream Stream { get { lock (_clientLock) { return _client.GetStream(); } } } /// /// Sending a message /// /// public virtual void SendMessage(string text) { var MessageLenght = _encoding.GetByteCount(text).ToString()+":";//At the beginning of the message is added it long in bytes var enumerable = _encoding.GetBytes(MessageLenght+text); lock (_streamLock) { try { Stream.Write(enumerable, 0, enumerable.Length); } catch (Exception e) { Debug.Print(e.Message); } } } /// /// Command to the beginning of the message waiting /// public virtual void BeginListenForMessage() { _stopListen = false; lock (_streamLock) { try { Stream.BeginRead(_bufer, 0, _bufer.Length, AsyncCallback, null); } catch (Exception e) { Debug.Print(e.Message); } } } /// /// Command to the end of the timeout messages /// public virtual void EndListenForMessage() { _stopListen = true; } /// /// Event for reading a message /// public event EventHandler MessageReaded; /// /// Event communications /// public event EventHandler ConnectionBroken; /// /// Connect to the IP /// /// /// /// public virtual bool Connect(string adres, int port) { lock (_clientLock) { _client?.Close(); try { _client = new TcpClient(adres, port); return true; } catch { return false; } } } /// /// Disable the Communicator /// public virtual void Disconect() { lock (_clientLock) { _client?.Close(); } } /// /// Pruser for receiving long messages /// protected Parser MessageLenght = from Lenght in Parse.Decimal select int.Parse(Lenght); /// /// The parser to receive the message body /// protected Parser MessageBody = from Lenght in Parse.Digit.Many() from spliter in the Parse.Char(':').Once() from body in the Parse.CharExcept('\\0').Many().Text() select body; /// /// Check the message for correctness /// (the actual long message pending) /// /// /// protected virtual bool IsCorrect(string message) { int Lenght = MessageLenght.Parse(message); string Body = MessageBody.Parse(message); try { if (Lenght == _encoding.GetByteCount(Body)) return true; } catch { // ignored } return false; } ~TcpCommunicatorBase() { _client.Close(); } /// /// Called when receiving a message /// /// protected virtual void AsyncCallback(IAsyncResult ar) { Message += _encoding.GetString(_bufer); while (Stream.DataAvailable)//if the message is longer than the buffer, then read it a few times { for (int i = 0; i < _bufer.Length; i++) _bufer[i] = 0; Stream.Read(_bufer, 0, _bufer.Length); Message += _encoding.GetString(_bufer); } if (IsCorrect(Message)) { //Check the message for correctness if (!_stopListen)//If the wire is not stopped { MessageReaded(this, new MessageReadedEventArgs { Message = MessageBody.Parse(Message) }); Message = String.Empty; BeginListenForMessage(); } Message = string.Empty; expectedMessageLenght = null; } } }

At some point, the server sends the message, and the client could not catch him (AsyncCallback does not start), despite the fact that the wire no disabled.
What could be the problem?
Enough whether the code is thread safe?
by | 9 views

1 Answer

0 like 0 dislike
1. To remove all the "lock" - no benefit from them here.

2. Remove all "try {...} catch (Exception e) { Debug.Print(e.Message); }
There is no benefit from them either.

3. Remove IsCorrect. Read the length of the message, then read the desired number of bytes. And what you call "Actual length" is a figment of your imagination.

4. No need to read as long as DataAvailable, and until then, until you get the desired number of bytes. Synchronously or asynchronously you do it - no difference.

5. And now the actual answer to your question:
The mechanism for reading messages dies when the reader reads faster than the writer writes (or network reports). In this case, DataAvailable will return false; in your algorithm, instead of having to wait for the remaining part of a message interrupts your reading in the middle of a message, said that IsCorrect() == false and hangs.

6. The message format makes sense to simplify: the first 4 bytes - length of body in bytes; then the body itself (for example, in UTF-8, if you need the text). Accordingly, read the first 4 bytes, and then another, as long as there indicated.

PS
7. Call Encoding.GetString() only on a General message; if you do this for part of a message - the result is unpredictable.

8. Network exceptions to handle, of course, necessary. However, Debug.Print is not the solution. The socket has a meaning close. And then - either to notify about the problem your customer (who processes the message), or in the good- try to open another connection and retry to continue the work so that the client did not notice anything :)
by
110,608 questions
257,186 answers
0 comments
35,649 users