0

I am working on a transportation Project RailWay. Let me explain the project :there are a lot of sensors during the path of the train ,so when the train passes one of these sensors ,the sensor sends a value to CTC(A computer that manages the sensors) server the value is 1 or 0 ,1 means that the train arrive the sensor and 0 means the train left the sensor ,so every thing is ok ,now here is the scope of my project:

The CTC server send the value to MY-SERVER for example :ID=16(SENSOR-ID),state=0.it means that the train left the sensor that its id is 16 ,Note:That i know the location of sensors by id .so My problems start here : the CTC server sends its data by TCP ,so i have to create a listener to listen the data that comes from the CTC server ,(Note:Sometimes the data that comes from CTC is a lot and maybe some data be lost) ,I create a program using c# that listen the port but sometimes the data that coes fro CTC are lost why ?

So let me explain my programs:

It's the code that i wrote to get the data :

class Server
{
    private TcpListener tcpListener;
    private Thread listenThread;

    public Server()
    {
        this.tcpListener = new TcpListener(IPAddress.Any, 3456);
        this.listenThread = new Thread(new ThreadStart(ListenForClients));
        this.listenThread.Start();
    }
    private void ListenForClients()
    {
        this.tcpListener.Start();

        while (true)
        {
            //blocks until a client has connected to the server
            TcpClient client = this.tcpListener.AcceptTcpClient();

            //create a thread to handle communication 
            //with connected client
            Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
            clientThread.Start(client);
        }
    }
    private void HandleClientComm(object client)
    {
      TcpClient tcpClient = (TcpClient)client;
      NetworkStream clientStream = tcpClient.GetStream();

      byte[] message = new byte[4096];
      int bytesRead;

      while (true)
      {
        bytesRead = 0;

        try
        {
          //blocks until a client sends a message
          bytesRead = clientStream.Read(message, 0, 4096);
        }
        catch
        {
          //a socket error has occured
          break;
        }

        if (bytesRead == 0)
        {
          //the client has disconnected from the server
          break;
        }

        //message has successfully been received
        ASCIIEncoding encoder = new ASCIIEncoding();
        System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead));
      }

      tcpClient.Close();
    }
}

And here i call the server class :

class Program
{
    static void Main(string[] args)
    {
        Server obj=new Server();
    }
}

The CTC code that sends data is like this(An example) :

static void Main(string[] args)
{
    TcpClient client = new TcpClient();
    IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3456);
    client.Connect(serverEndPoint);
    using (NetworkStream clientStream = client.GetStream())
    {
        ASCIIEncoding encoder = new ASCIIEncoding();
        byte[] buffer = encoder.GetBytes("Hello Server!");
        clientStream.Write(buffer, 0, buffer.Length);
    }
}

But sometimes my programs(SERVER CODE) lost data ?!!!Why ?Any idea ?

Best regards

vrajs5
  • 4,066
  • 1
  • 27
  • 44
Ehsan Akbar
  • 6,977
  • 19
  • 96
  • 180
  • How can change it to one thread !!!i think i create a connection for every thread !!!maybe it causes the error . – Ehsan Akbar May 27 '14 at 06:19
  • Looks like you open a new connection everytime you want to send something. Better code a class _client_ and pass the TcpClient to that class. In the class you have one public method _send_, which will handle the data that should be passed to the client. Im using StreamReader and StreamWriter for such things as I think they are easier to understand an programm. I will add an example soon. – Kimmax May 27 '14 at 06:28
  • @Kimmax will be appreciated i you do that ,so i don't want to put my code in while loop ?can i prevent this ? – Ehsan Akbar May 27 '14 at 06:29
  • 1
    Please, have look on [this](http://stackoverflow.com/questions/869744/how-to-write-a-scalable-tcp-ip-based-server), it could be help full for designing TCP Server..!! – H. Mahida May 27 '14 at 06:38
  • Can't help with the actual problem, but I would suggest using `BeginReceive()` type of socket programming. You don't need any threads or synchronization and still get nice background data handling. – Sami Kuhmonen May 27 '14 at 06:41
  • @SamiKuhmonen could you give me an example ? – Ehsan Akbar May 27 '14 at 06:47
  • 1
    @EA I added some code. I think you could get it running with that – Kimmax May 27 '14 at 14:26

2 Answers2

3

Here is my solution of a basic Client/Server application using StreamReader and StreamWriter

Basic structure

The server will be running a TcpListener. We will use the Pending() method to check for waiting connections while not blocking the thread from exiting. When a new connection is waiting we will accept it with the AcceptTcpClient(), create a new instance of our own Client class and add it to a List<Client()> to mange it later. The class Client will store the methods to send data and hold informations like ID etc.

Code

Server Class:

using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace CTCServer
{
    class Server
    {
        //Stores the IP Adress the server listens on
        private IPAddress ip;

        //Stores the port the server listens on
        private int port;

        //Stores the counter of connected clients. *Note* The counter only gets increased, it acts as "id"
        private int clientCount = 0;

        //Defines if the server is running. When chaning to false the server will stop and disconnect all clients.
        private bool running = true;

        //Stores all connected clients.
        public List<Client> clients = new List<Client>();

        //Event to pass recived data to the main class
        public delegate void GotDataFromCTCHandler(object sender, string msg);
        public event GotDataFromCTCHandler GotDataFromCTC;

        //Constructor for Server. If autoStart is true, the server will automaticly start listening.
        public Server(IPAddress ip, int port, bool autoStart = false)
        {
            this.ip = ip;
            this.port = port;

            if (autoStart) 
                this.Run();
        }

        //Starts the server.
        public void Run()
        {
            //Run in new thread. Otherwise the whole application would be blocked
            new Thread(() =>
            {
                //Init TcpListener
                TcpListener listener = new TcpListener(this.ip, this.port);

                //Start listener
                listener.Start();

                //While the server should run
                while (running)
                {
                    //Check if someone wants to connect
                    if (listener.Pending())
                    {
                        //Client connection incoming. Accept, setup data incoming event and add to client list
                        Client client = new Client(listener.AcceptTcpClient(), this.clientCount);

                        //Declare event
                        client.internalGotDataFromCTC += GotDataFromClient;

                        //Add to list
                        clients.Add(client);

                        //Increase client count
                        this.clientCount++;
                    }
                    else
                    {
                        //No new connections. Sleep a little to prevent CPU from going to 100%
                        Thread.Sleep(100);
                    }
                }

                //When we land here running were set to false or another problem occured. Stop server and disconnect all.
                Stop();
            }).Start(); //Start thread. Lambda \(o.o)/
        }

        //Fires event for the user
        private void GotDataFromClient(object sender, string data)
        {
            //Data gets passed to parent class
            GotDataFromCTC(sender, data);
        }

        //Send string "data" to all clients in list "clients"
        public void SendToAll(string data)
        {
            //Call send method on every client. Lambda \(o.o)/
            this.clients.ForEach(client => client.Send(data));
        }

        //Stop server
        public void Stop()
        {
            //Exit listening loop
            this.running = false;

            //Disconnect every client in list "client". Lambda \(o.o)/
            this.clients.ForEach(client => client.Close());

            //Clear clients.
            this.clients.Clear();
        }
    }
}

Client Class

using System.IO;
using System.Net.Sockets;
using System.Threading;

namespace CTCServer
{
    class Client
    {
        //Stores the TcpClient
        private TcpClient client;

        //Stores the StreamWriter. Used to write to client
        private StreamWriter writer;

        //Stores the StreamReader. Used to recive data from client
        private StreamReader reader;

        //Defines if the client shuld look for incoming data
        private bool listen = true;

        //Stores clientID. ClientID = clientCount on connection time
        public int id;

        //Event to pass recived data to the server class
        public delegate void internalGotDataFromCTCHandler(object sender, string msg);
        public event internalGotDataFromCTCHandler internalGotDataFromCTC;

        //Constructor
        public Client(TcpClient client, int id)
        {
            //Assain members
            this.client = client;
            this.id = id;

            //Init the StreamWriter
            writer = new StreamWriter(this.client.GetStream());
            reader = new StreamReader(this.client.GetStream());

            new Thread(() =>
            {
                Listen(reader);
            }).Start();
        }

        //Reads data from the connection and fires an event wih the recived data
        public void Listen(StreamReader reader)
        {
            //While we should look for new data
            while(listen)
            {
                //Read whole lines. This will read from start until \r\n" is recived!
                string input = reader.ReadLine();

                //If input is null the client disconnected. Tell the user about that and close connection.
                if (input == null)
                {
                    //Inform user
                    input = "Client with ID " + this.id + " disconnceted.";
                    internalGotDataFromCTC(this, input);

                    //Close
                    Close();

                    //Exit thread.
                    return;
                }

                internalGotDataFromCTC(this, input);
            }
        }

        //Sends the string "data" to the client
        public void Send(string data)
        {
            //Write and flush data
            writer.WriteLine(data);
            writer.Flush();
        }

        //Closes the connection
        public void Close()
        {
            //Stop listening
            listen = false;

            //Close streamwriter FIRST
            writer.Close();

            //Then close connection
            client.Close();
        }
    }
}

Test code. Note: this is a console application!

using System;
using System.Net;

namespace CTCServer
{
    class Program
    {
        static void Main(string[] args)
        {
            //Set title
            Console.Title = "CTC-Server";

            //Create new instance of the server
            Server server = new Server(IPAddress.Any, 1221);

            //Handle GotDataFromCTC
            server.GotDataFromCTC += GotDataFromCTC;

            //Start the server. We could use the autoStart in constructor too.
            server.Run();

            //Inform about the running server
            Console.WriteLine("Server running");


            //Listen for input.
            while(true)
            {
                //Read input line from cmd
                string input = Console.ReadLine();

                //Stores the command itself
                string command;

                //Stores parameters
                string param  = "";

                //If input line contains a whitespace we have parameters that need to be processed.
                if(input.Contains(" "))
                {
                    //Split the command from the parameter. Parte before whitespace = command, rest = parameters
                    command = input.Split(' ')[0];
                    param = input.Substring(command.Length +1);
                }
                else
                {
                    //No whitespace, so we dont have any parameters. Use whole input line as command.
                    command = input;
                }

                //Process the command
                switch(command)
                {
                    //Sends a string to all clients. Everything behind "send " (Note the whitespace) will be send to the client. Exanple "send hello!" will send "hello!" to the client.
                    case "send":
                    {
                        //Give some feedback
                        Console.WriteLine("Send to all clients: {0}", param);

                        //Send data
                        server.SendToAll(param);

                        //Done
                        break;
                    }

                    //Closes connection to all clients and exits. No parameters.
                    case "exit":
                    {
                        //Stop the server. This will disconncet all clients too.
                        server.Stop();

                        //Clean exit
                        Environment.Exit(0);

                        //Done. We wont get here anyway.
                        break;
                    }
                }
            }
        }

        //Recived data from clien. Show it!
        static void GotDataFromCTC(object sender, string data)
        {
            Console.WriteLine("Data from CTC-Server with ID {0} recived:\r\n{1}", (sender as Client).id, data);
        }
    }
}

NOTE that this application doesnt have any exception handling. I did this to show a direction, you will need to modify the code to fit to your requirements. Let me know if you need something.
Example Project (Visual Studio 2013 Pro): Download | Virustoal

Kimmax
  • 1,658
  • 21
  • 34
  • I missed that you dont want to send the data but recive it. Well I will add it to the client. – Kimmax May 27 '14 at 14:30
0

I found an article about Socket programming that using StreamReader ,It using one thread ,and no information lost is happened

You can take a look here :

http://www.codeproject.com/Articles/511814/Multi-client-per-one-server-socket-programming-in

Ehsan Akbar
  • 6,977
  • 19
  • 96
  • 180