/// ---------------------------------------------------------------------------------------- /// TCP Demo (Server side) /// (c) by Vector Informatics GmbH /// /// /// Hints: /// - If reference to "System" is missing you have to add it manually. /// /// - To use SystemVariables, you have to be sure the generated "...sysvars.dll" is within your references. /// If not, add it by browsing to the file. /// ---------------------------------------------------------------------------------------- /// using System; using Vector.Tools; using Vector.CANoe.Runtime; using Vector.CANoe.Sockets; using System.Runtime.Remoting.Messaging; using System.Collections.Generic; /// /// ---------------------------------------------------------------------------------------- /// TcpServerNode Measurement Script class. /// This represent the CANoe-Simulation node, that is a basic MeasurementScript /// that will initialize a TcpServer, doing the networking stuff. /// ---------------------------------------------------------------------------------------- /// public class TcpServerNode : MeasurementScript { /// /// initialize measurement /// public override void Initialize() { this.Server = new TcpServer(); } /// /// start measurement /// public override void Start() { if (NSys.TcpServer.AutoStart.Value.Equals(1)) { NSys.TcpServer.Status.Value = 1; // start server over sysvar to have the panel reflect the state. } } /// /// stop measurement /// public override void Stop() { this.Server.Stop(); } /// /// shutdown measurement /// public override void Shutdown() { } /// /// on changing the server's state... /// [OnChange(typeof(NSys.TcpServer.Status))] public void OnSysVarStatusChanged() { if (NSys.TcpServer.Status.Value.Equals(1)) { this.Server.Start(); } else { this.Server.Stop(); } } /// /// server instance. /// private TcpServer Server { get; set; } } /// /// ---------------------------------------------------------------------------------------- /// The main TCP server class. /// /// Demonstrates how to work with the TCP networking classes. /// ---------------------------------------------------------------------------------------- /// internal class TcpServer { /// /// constant integer for the TCP-Buffer's max size. /// this has nothing to do with a MTU or something. Its just the buffer where the data of the /// network stream can be buffered as byte array. /// private const int TCP_DATA_SIZE = 8192; /// /// constructor /// public TcpServer() { this.Running = false; } /// /// start the server. /// public void Start() { // stop server (if already running) this.Stop(); // start listening on configured port... var serverIP = System.Net.IPAddress.Parse(NSys.TcpServer.IP.Value); var serverPort = NSys.TcpServer.Port.Value; this.TcpListenSocket = new TcpListener(serverIP, serverPort); this.TcpListenSocket.Start(); this.AwaitIncomingClient(); this.Running = true; Output.WriteLine("Server Started."); } /// /// await incoming client on listen socket... /// private void AwaitIncomingClient() { this.TcpListenSocket.BeginAcceptTcpClient(this.OnTcpClientConnectingCallback, null); } /// /// On TCP client connects to listen socket... /// /// Operation result is given into this callback private void OnTcpClientConnectingCallback( IAsyncResult result ) { if (result != null) { Output.WriteLine("Server: Incoming client."); // accept the client... var clientEntry = new ClientEntry(); this.ConnectedClients.Add(clientEntry); clientEntry.Client = this.TcpListenSocket.EndAcceptTcpClient(result); // continue awaiting new clients on listen socket... this.AwaitIncomingClient(); // say welcome to the client... Output.WriteLine("Server: Welcome client..."); this.SendResponse(clientEntry, "WELCOME"); // start receiving data from the client's network stream... this.ReceiveRequest(clientEntry); } } /// /// stop the server /// public void Stop() { if (this.Running) { if (this.TcpListenSocket != null) { this.TcpListenSocket.Stop(); this.TcpListenSocket = null; } this.Running = false; if (this.ConnectedClients.Count > 0) { Output.WriteLine("Server: Stopping..."); } foreach (var clientEntry in this.ConnectedClients.ToArray()) { this.DisconnectClient(clientEntry); } Output.WriteLine("Server Stopped."); } } /// /// on reading from nwtwork stream done. /// /// The result of the network operation is given into this callback. private void OnReadDoneCallback( IAsyncResult result ) { if (result != null) { var clientEntry = (ClientEntry)result.AsyncState; clientEntry.Client.GetStream().EndRead(result); if (result.IsCompleted) { var dataString = System.Text.Encoding.UTF8.GetString(clientEntry.TcpData).Split('\0')[0]; Output.WriteLine("Server: Received data from client: " + dataString); // react on request... this.ReactOnRequest(clientEntry, dataString); // continue reading from client... this.ReceiveRequest(clientEntry); } else { // incomplete... disconnect client. Output.WriteLine("Server: Reading from network stream not completed."); this.DisconnectClient(clientEntry); } } } /// /// Disconnect client with given client info /// /// private void DisconnectClient( ClientEntry clientEntry ) { Output.WriteLine("Server: Closing server side client socket."); clientEntry.Client.Close(); this.ConnectedClients.Remove(clientEntry); } /// /// simple server logics acting on received data. /// /// /// the request to react on. private void ReactOnRequest( ClientEntry clientEntry, string dataString ) { // --------------------------------------------------------------------------- // THIS IS A SIMPLE SERVER LOGICS THAT ACTS ON RECEIVED DATA... // --------------------------------------------------------------------------- // send back "OK" followed by the upper-string if the string can be converted to upper, // else send "NOT CONVERTED". if (dataString.ToUpper() == dataString) { Output.WriteLine("Server: Client data string is not convertible. Send NOT CONVERTED."); this.SendResponse(clientEntry, "NOT CONVERTED"); } else { Output.WriteLine("Server: converting client's data string and send it back..."); this.SendResponse(clientEntry, "OK"); this.SendResponse(clientEntry, dataString.ToUpper()); } // --------------------------------------------------------------------------- // DONE // --------------------------------------------------------------------------- } /// /// send data to the client. /// /// /// Data as string to send to the client. private void SendResponse( ClientEntry clientEntry, string data ) { if (clientEntry.Client != null) { try { clientEntry.Client.GetStream().BeginWrite(System.Text.Encoding.UTF8.GetBytes(data), 0, data.Length, this.OnWriteDoneCallback, clientEntry); } catch (Exception /*e*/) { Output.WriteLine("Server: Exception on writing to network stream."); this.DisconnectClient(clientEntry); } } } /// /// receive from given client... /// /// private void ReceiveRequest( ClientEntry clientEntry ) { if (clientEntry.Client.Connected) { Output.WriteLine("Server: Awaiting request..."); Array.Clear(clientEntry.TcpData, 0, clientEntry.TcpData.Length); try { clientEntry.Client.GetStream().BeginRead(clientEntry.TcpData, 0, clientEntry.TcpData.Length, this.OnReadDoneCallback, clientEntry); } catch(Exception /*e*/) { Output.WriteLine("Server: Exception on reading from network stream."); this.DisconnectClient(clientEntry); } } else { Output.WriteLine("Server: Can't receive from client socket due socket is not connected."); this.DisconnectClient(clientEntry); } } /// /// writing data to socket done. /// /// Result of network operation is given into this callback private void OnWriteDoneCallback( IAsyncResult result ) { if (result != null) { var clientEntry = (ClientEntry)result.AsyncState; clientEntry.Client.GetStream().EndWrite(result); if (!result.IsCompleted) { // incomplete... disconnect client. Output.WriteLine("Server: Writing to network stream not completed."); this.DisconnectClient(clientEntry); } } } /// /// server running indicator. /// private bool Running { get; set; } /// /// client info. consists of a socket, and a Byte-Buffer for the Tcp data. /// private class ClientEntry { public TcpClient Client = null; public byte[] TcpData = new byte[TCP_DATA_SIZE]; } /// /// tcp listen socket accepting incoming clients... /// private TcpListener TcpListenSocket { get; set; } /// /// keep track of all connected clients in case the server stops /// it has to disconnect all connected clients... /// private List ConnectedClients = new List(); }