0

I'm very new to all that TCP thing and I just can't find what's going wrong here. It might be pretty obvious for some of you. When I run the code, I run the Start process on the Server side, it displays 'waiting for connection', then I start the client, the later displays 'connected to ', I relaunch the start process on the server side and it displays 'Connected to the client' and then, on both sides, when I call the method SendThroughTCPSocket("whatever string"), I can see it being sent but nothing is being detected on the other side ?
What could I be doing wrong ? How could I have both of them constantly listening to each other ?

SERVER SIDE :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Server
{
// State object for reading client data asynchronously
public class StateObject
{

    #region instance variables

    // Client  socket.
    public Socket workSocket = null;
    // Size of receive buffer.
    public const int BufferSize = 1024;
    // Receive buffer.
    public byte[] buffer = new byte[BufferSize];
    // Received data string.
    public StringBuilder sb = new StringBuilder();

    #endregion

}

public class AsynchronousSocketListener
{

    public enum TransmissionSate
    {
        Waiting,
        Receiving,
        Received,
        Sending,
        Sent,
        Off
    }


    #region class variables

    // Thread signal.
    public static ManualResetEvent allDone = new ManualResetEvent(false);

    public static IPHostEntry ipHostInfo;
    public static IPAddress ipAddress;
    public static IPEndPoint localEndPoint;

    public static Socket listener;
    public static Socket handler;


    //flags
    public static TransmissionSate currentState = TransmissionSate.Off;

    #endregion

    #region constructor

    public AsynchronousSocketListener()
    {
    }

    #endregion

    #region Start Listening

    //Start Listening for Client
    public static void StartListening()
    {
        // Data buffer for incoming data.
        byte[] bytes = new Byte[1024];

        // Establish the local endpoint for the socket.
        // The DNS name of the computer
        ipHostInfo = Dns.Resolve(Dns.GetHostName());
        ipAddress = ipHostInfo.AddressList[0];
        localEndPoint = new IPEndPoint(ipAddress, 11000);

        // Create a TCP/IP socket.
        listener = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp);

        // Bind the socket to the local endpoint and listen for incoming connections.
        try
        {
            listener.Bind(localEndPoint);
            listener.Listen(100);

            while (true)
            {
                // Set the event to nonsignaled state.
                allDone.Reset();

                // Start an asynchronous socket to listen for connections.
                Console.WriteLine("Waiting for a connection...");
                listener.BeginAccept(
                    new AsyncCallback(AcceptCallback),
                    listener);

                //flag
                currentState = TransmissionSate.Waiting;

                // Wait until a connection is made before continuing.
                allDone.WaitOne();
            }

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }


        Console.WriteLine("\nConnected to the client.");
        //Console.Read();

    }

    #endregion

    #region Receive Methods

    //Accept communication and Start reading
    public static void AcceptCallback(IAsyncResult ar)
    {
        // Signal the main thread to continue.
        allDone.Set();

        // Get the socket that handles the client request.
        listener = (Socket)ar.AsyncState;
        handler = listener.EndAccept(ar);

        //flag
        currentState = TransmissionSate.Receiving;

        // Create the state object.
        StateObject state = new StateObject();
        state.workSocket = handler;
        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
            new AsyncCallback(ReadCallback), state);
    }

    //Read and handle the information
    public static void ReadCallback(IAsyncResult ar)
    {
        String content = String.Empty;

        // Retrieve the state object and the handler socket
        // from the asynchronous state object.
        StateObject state = (StateObject)ar.AsyncState;
        handler = state.workSocket;

        // Read data from the client socket. 
        int bytesRead = handler.EndReceive(ar);

        if (bytesRead > 0)
        {
            // There  might be more data, so store the data received so far.
            state.sb.Append(Encoding.ASCII.GetString(
                state.buffer, 0, bytesRead));

            // Check for end-of-file tag. If it is not there, read 
            // more data.
            content = state.sb.ToString();
            if (content.IndexOf("<EOF>") > -1)
            {

                //flag 
                currentState = TransmissionSate.Received;

                // All the data has been read from the 
                // client. Display it on the console.
                Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
                    content.Length, content);

                //reference
                Data.lastResponse = content;

                //react
                Console.WriteLine("Server just received a request");
                switch (content)
                {
                    case "DataRequest":
                        Console.WriteLine("Client is trying to get the preset data");
                        SendThroughTCPSocket(Data.xmlToSend + Data.endOfFile);
                        break;

                    default:
                        Console.WriteLine("Unknown request from Client");
                        break;
                }

            }
            else
            {
                // Not all data received. Get more.
                handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReadCallback), state);
            }
        }
    }

    #endregion

    #region Send Methods

    //Send data to a socket
    private static void Send(Socket handler, String data)
    {
        // Convert the string data to byte data using ASCII encoding.
        byte[] byteData = Encoding.ASCII.GetBytes(data);

        //flag
        currentState = TransmissionSate.Sending;

        // Begin sending the data to the remote device.
        handler.BeginSend(byteData, 0, byteData.Length, 0,
            new AsyncCallback(SendCallback), handler);
    }

    //Sending data and closing handler
    private static void SendCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the socket from the state object.
            Socket handler = (Socket)ar.AsyncState;

            // Complete sending the data to the remote device.
            int bytesSent = handler.EndSend(ar);
            Console.WriteLine("Sent {0} bytes to client.", bytesSent);

            //flag
            currentState = TransmissionSate.Sent;

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    #endregion

    #region SendThroughTCPSocket

    public static void SendThroughTCPSocket(String data)
    {
        try
        {
            // Send data to the client
            Send(handler, data);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }

    }

    #endregion

    #region Stop Server

    //Close Sever  
    public static void StopServer()
    {
        try
        {
            // Release the socket.
            handler.Shutdown(SocketShutdown.Both);
            handler.Close();

            //flag
            currentState = TransmissionSate.Off;

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    #endregion

}
}

CLIENT SIDE :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Client
{
// State object for receiving data from remote device.
public class StateObject
{


    #region instance variables

    // Client socket.
    public Socket workSocket = null;
    // Size of receive buffer.
    public const int BufferSize = 256;
    // Receive buffer.
    public byte[] buffer = new byte[BufferSize];
    // Received data string.
    public StringBuilder sb = new StringBuilder();

    #endregion

}

public class AsynchronousClient
{

    public enum TransmissionSate
    {
        Waiting,
        Receiving,
        Received,
        Sending,
        Sent,
        Off
    }


    #region instance variables

    // The port number for the remote device.
    private const int port = 11000;

    #endregion

    #region class variables

    // ManualResetEvent instances signal completion.
    private static ManualResetEvent connectDone =
        new ManualResetEvent(false);
    private static ManualResetEvent sendDone =
        new ManualResetEvent(false);
    private static ManualResetEvent receiveDone =
        new ManualResetEvent(false);

    // The response from the remote device.
    private static String response = String.Empty;

    public static IPHostEntry ipHostInfo;
    public static IPAddress ipAddress;
    public static IPEndPoint remoteEP;

    public static Socket client;

    //flags
    public static TransmissionSate currentState = TransmissionSate.Off;
    public static bool isConnected = false;

    #endregion

    #region Start Client

    //Start Client and use it 
    public static void StartClient()
    {
        // Connect to a remote device.
        try
        {
            //flag 
            isConnected = false;

            // Establish the remote endpoint for the socket.
            // The name of the host
            // remote device is the current device
            ipHostInfo = Dns.Resolve(Dns.GetHostName());
            ipAddress = ipHostInfo.AddressList[0];
            remoteEP = new IPEndPoint(ipAddress, port);

            // Create a TCP/IP socket.
            client = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);

            // Connect to the remote endpoint.
            client.BeginConnect(remoteEP,
                new AsyncCallback(ConnectCallback), client);
            connectDone.WaitOne();

            //flag
            currentState = TransmissionSate.Waiting;

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    #endregion

    #region Stop Client

    //Close Client 
    public static void StopClient()
    {
        try
        {
            // Release the socket.
            client.Shutdown(SocketShutdown.Both);
            client.Close();

            //flag
            currentState = TransmissionSate.Off;
            isConnected = false;

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    #endregion

    #region Connect

    //callback for connection
    private static void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the socket from the state object.
            Socket client = (Socket)ar.AsyncState;

            // Complete the connection.
            client.EndConnect(ar);

            Console.WriteLine("Socket connected to {0}",
                client.RemoteEndPoint.ToString());

            // Signal that the connection has been made.
            connectDone.Set();

            //flag
            isConnected = true;
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    #endregion

    #region Receive

    //Receive data
    private static void Receive(Socket client)
    {
        try
        {
            // Create the state object.
            StateObject state = new StateObject();
            state.workSocket = client;

            //flag
            currentState = TransmissionSate.Receiving;

            // Begin receiving the data from the remote device.
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReceiveCallback), state);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    //callback Receive
    private static void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the state object and the client socket 
            // from the asynchronous state object.
            StateObject state = (StateObject)ar.AsyncState;
            Socket client = state.workSocket;

            // Read data from the remote device.
            int bytesRead = client.EndReceive(ar);

            if (bytesRead > 0)
            {
                // There might be more data, so store the data received so far.
                state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));

                // Get the rest of the data.
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReceiveCallback), state);
            }
            else
            {
                // All the data has arrived; put it in response.
                if (state.sb.Length > 1)
                {
                    response = state.sb.ToString();
                }
                // Signal that all bytes have been received.
                receiveDone.Set();

                //flag 
                currentState = TransmissionSate.Received;
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    #endregion

    #region Send

    //Send data
    private static void Send(Socket client, String data)
    {
        // Convert the string data to byte data using ASCII encoding.
        byte[] byteData = Encoding.ASCII.GetBytes(data);

        //flag
        currentState = TransmissionSate.Sending;

        // Begin sending the data to the remote device.
        client.BeginSend(byteData, 0, byteData.Length, 0,
            new AsyncCallback(SendCallback), client);
    }

    //Callback send
    private static void SendCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the socket from the state object.
            Socket client = (Socket)ar.AsyncState;

            // Complete sending the data to the remote device.
            int bytesSent = client.EndSend(ar);
            Console.WriteLine("Sent {0} bytes to server.", bytesSent);

            // Signal that all bytes have been sent.
            sendDone.Set();

            //flag
            currentState = TransmissionSate.Sent;
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    #endregion

    #region SendThroughTCPSocket

    public static string SendThroughTCPSocket(String data)
    {
        try
        {
            // Send data to the remote device.
            Send(client, data);
            sendDone.WaitOne();

            // Receive the response from the remote device.
            Receive(client);
            receiveDone.WaitOne();

            // Write the response to the console.
            Console.WriteLine("Response received : {0}", response);

            return response;
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            return "<No response>";
        }

    }

    #endregion

}
}
vbuzze
  • 930
  • 1
  • 11
  • 25

1 Answers1

1

You need to implement a protocol on top of the socket. In your server you're using "" to determine that a message has ended and you only print it out once you get this. However, I can see nowhere in the client where you do this. Ideally you want to have a start of message token and an end of message token so that you can send multiple messages over a socket. Change your client send method to

   private static void Send(Socket client, String data)
    {
        // Convert the string data to byte data using ASCII encoding.
        byte[] byteData = Encoding.ASCII.GetBytes(data + "<EOF>");

        //flag
        currentState = TransmissionSate.Sending;

        // Begin sending the data to the remote device.
        client.BeginSend(byteData, 0, byteData.Length, 0,
            new AsyncCallback(SendCallback), client);
    }

and this should work, but I do recommend implementing a protocol with start and end tokens.

In the receivecallback of the client you have code that never checks for any kind of protocol and simply attempts to keep on receiving data:

  if (bytesRead > 0)
            {
                // There might be more data, so store the data received so far.
                state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));

                // Get the rest of the data.
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReceiveCallback), state);
            }

At some stage your program must check the data to see if there is an end token of some sort. Try changing this to the following:

                if (bytesRead > 0)
            {
                // There might be more data, so store the data received so far.
                state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
                var endPos = state.sb.ToString().IndexOf("<EOF>");
                if (endPos > -1) //we have a complete message. huzzah!
                {
                    response = state.sb.ToString().Substring(0, endPos);
                    // Signal that all bytes have been received.
                    receiveDone.Set();
                    //flag 
                    currentState = TransmissionSate.Received;
                }
                else
                // Get the rest of the data.
                    client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReceiveCallback), state);
            }

I must reiterate: you need to design a protocol if you are going to use raw sockets: a way to identify the start and end of discreet messages.

Kell
  • 3,252
  • 20
  • 19
  • I did omit the EOF tag, now that I've added it, and trimmed it on the server side after being received, the server tells me it did understand the request, it did replied by sending the appropriate string + EOF tag, but on the client side nothing is caught as a response. However, when I'm using SendThroughTCPSocket() I first send the data and I do switch to the "wait to receive state" on the Client side. Any idea ? – vbuzze Nov 30 '16 at 14:34
  • It is received only when the server Closes the connection – vbuzze Nov 30 '16 at 14:55
  • I'm sorry to ask this, but have you tried debugging this? Again, on the client it looks like there is no protocol in place, so you check if the size of the bytes recieved is bigger then 0 and if so continue to receive. You never check anywhere if you've got an end of message. see edit – Kell Dec 01 '16 at 12:49