// // Client.cs // // Author: // Di MERCURIO Sébastien // // Copyright (c) 2018 INSA - DGEI // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . using System; using System.Net.Sockets; using System.Text; using System.Threading; namespace monitor { /// /// Static class for TCP client /// public static class Client { /// /// Default server name /// public const string defaultIP = "10.105.1.13"; /// /// Default server port number /// public const int defaultPort = 5544; /// /// Tcp client object /// private static TcpClient client = null; /// /// Stream object used for communication /// private static NetworkStream stream = null; /// /// Size of internal buffer used when reading data from server /// private const int BufferMaxSize = 8*1024; /// /// Internal buffer used when reading data from server /// private static byte[] buffer = new byte[BufferMaxSize]; /// /// String containing received message from tcp server /// private static StringBuilder message = new StringBuilder(); /// /// Callback to send received message to upper level /// public delegate void ReadEvent(string msg); public static ReadEvent readEvent = null; /// /// Open connection to server "host", on default port number. /// /// true if connection succeded, false otherwise /// Hostname to connect to public static bool Open(string host) { return Client.Open(host, defaultPort); } /// /// Open connection to server "host", with port number "port" /// /// true if connection succeded, false otherwise /// Hostname to connect to /// Port number for connection public static bool Open(string host, int port) { bool status = true; try { client = new TcpClient(host, port); stream = client.GetStream(); // Start reading tcp stream and call "ReadCallback" method when newLength data // will be received // initially, "newLength" is equal to 1, so first call to ReadCallback // will be done after reception of 1 byte. // received data are stored in buffer // Next reading will be done in ReadCallback method stream.BeginRead(buffer, 0, 1, new AsyncCallback(ReadCallback), message); } catch (ArgumentNullException e) { Console.WriteLine("ArgumentNullException: " + e); status = false; } catch (SocketException e) { Console.WriteLine("SocketException: " + e.ToString()); status = false; } catch (Exception e) { Console.WriteLine("Unknown Exception: " + e.ToString()); status = false; } return status; } /// /// Close connection to server /// public static void Close() { if (stream != null) stream.Close(); if (client != null) client.Close(); } /// /// Callback call by stream.BeginRead after reception of newLength data /// /// Not sure of what is it, but needed for terminate reading private static void ReadCallback(IAsyncResult ar) { int newLength = 1; int index = -1; if (client.Connected) { int bytesRead; try { // Terminate read operation, and get number of byte stored in buffer bytesRead = stream.EndRead(ar); } catch (ObjectDisposedException e) { Console.WriteLine("Connection to server dropped: " + e.ToString()); return; } catch (System.IO.IOException e) { Console.WriteLine("Connection to server dropped: " + e.ToString()); return; } newLength = 1; index = -1; // if number of byte read is not 0, concatenate string and buffer if (bytesRead > 0) { //Console.WriteLine("Receive " + bytesRead + " data"); // Append new data to current string (expecting data are ascii) message.Append(Encoding.ASCII.GetString(buffer, 0, bytesRead)); index = SearchCarriageReturn(buffer, bytesRead); } // if it remains received data, prepare for a new reading (get another buffer to append to current one) if (index == -1) { if (client.Available > 0) { newLength = client.Available; if (newLength > BufferMaxSize) newLength = BufferMaxSize; else newLength = client.Available; } } else { string s = message.ToString(); // no more data to read, buffer and string can be send to upper level readEvent?.Invoke(s); message.Clear(); if (index != bytesRead - 1) { byte[] trailing=new byte[BufferMaxSize]; Array.Copy(buffer, index + 1, trailing, 0, bytesRead - index - 1); message.Append(Encoding.ASCII.GetString(trailing, 0, bytesRead - index - 1)); } } // Prepare for reading new data if (newLength> BufferMaxSize) newLength = BufferMaxSize; if (newLength <= 0) newLength = 1; try { stream.BeginRead(buffer, 0, newLength, new AsyncCallback(ReadCallback), message); } catch (ObjectDisposedException e) { Console.WriteLine("Connection to server dropped: " + e.ToString()); return; } catch (System.IO.IOException e) { Console.WriteLine("Connection to server dropped: " + e.ToString()); return; } } } /// /// Searchs the carriage return. /// /// Index of carriage return, if present, -1 otherwise. /// Buffer of byte /// Length of buffer private static int SearchCarriageReturn(byte[] buf, int length) { int index = -1; int i = 0; for (i = 0; i < length; i++) { if (buf[i] == (byte)'\n') break; } if (i!= length) index = i; return index; } /// /// Write a string to server /// /// Nothing /// Message to send to server public static void Write(string mes) { if (client.Connected) { byte[] writeBuffer = Encoding.UTF8.GetBytes(mes); try { stream.Write(writeBuffer, 0, mes.Length); } catch (System.IO.IOException) { Console.WriteLine("Server closed"); client.Close(); } } } } }