hypheni
hypheni

Reputation: 816

c# tcp socket receive loop break logic

I'm writng a c# tcp socket server which will receive data from c++ socket application. Now everything works good except the loop break logic inside my c# receiving thread. I'm showing a code snippet below to explain better.

    //creating socket object
    private Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    //accepting connections
     TcpListener tcpListener = new TcpListener(ipAdd, iPort);
     tcpListener.Start();
     this.socket = tcpListener.AcceptSocket();
     tcpListener.Stop();        

    //code for 
    //public byte[] ReceiveMessage(ref int intError)
    while (this.socket.Available > 0)
    {
      try
      {
        intBytesReceived = this.socket.Receive(byteReceivedBuffer, byteReceivedBuffer.Length, SocketFlags.None);
        Thread.Sleep(100);
      }
      catch (SocketException ex)
      {
        string str = ex.Message;
        intError = -1;
      }
    }

Below is the thread function to receive data continuously

  //Thread to continuous poll data from client
  //Now this has been done as I need to receive multiple messages from client after server ack received at client side. 

  //Thread quit logic based on manual stop button press
  //I want to have one more logic by which thread will exit if the connection closed by client socket. i.e. a call of 'CloseSocket()' function from c++ application.     

  if (TCPServerListener.serverStatus == TCPServerListener.ServerStatus.Stopped)
  {
    tcpCommunication.Disconnect();
    break;
  }

  while(true)
  {
    int sockError = 0;
    byte[] byteData = tcpCommunication.ReceiveMessage(ref sockError);
    if (byteData.Length > 0)
    {
      ParseBuffer(byteData, ref tcpCommunication);
    }
  }

For better picture I'm wrting below my communication protocol.

  1. Client initiate a connection. Send a data set
  2. Server receives, process, send ack
  3. Client is in halt mode until it receive the ack from server, but didn't close the socket
  4. This time, server will not receive any message but the receiving thread should active as I'm creating a single thread for each client.
  5. Once the client receives the ack it will continue to send next data
  6. Server receiving thread will get data now and process accordingly
  7. Once client closes down its socket, server receiver thread should close also

I'm able to getting my work done but the server receiver thread is not getting closed. That's my problem. Any suggestions would be a off great help.

Upvotes: 0

Views: 4940

Answers (1)

Shar1er80
Shar1er80

Reputation: 9041

It has been my experience that when you use a TCP server/client socket relationship, the TCP server socket side will be in a thread that is controlled by a flag to continue listening until told to stop (Your comments mention a stop button).

The client side runs until all data is done, or the same flag controlling the server side is tripped.

When a client connects, I would store the AcceptSocket into a list. When I did this, I had a custom class that the takes the AcceptSocket and the custom class had counters for like how many messages, or bytes was sent/received to/from this client.

// This should be a threaded method if you're using a button to stop
private void StartTcpListener()
{
    List<ClientClass> clientClassList = new List<ClientClass>();

    TcpListener tcpListener = new TcpListener(ipAdd, iPort);
    tcpListener.Start();

    while (keepListening)
    {
        Socket socket = tcpListener.AcceptSocket();

        // Create a client object and store it in a list
        ClientClass clientClass = new ClientClass(socket);
        clientClassList.Add(clientClass);

        // This method would start a thread to read data from the accept socket while it was connected.
        clientClass.Start();
    }

    foreach (ClientClass client in clientClassList)
    {
        // This method would stop the thread that reads data from the accept socket and close the accept socket
        client.Stop();
    }
    tcpListener.Stop();
}

For the client side, when reading from the client accept socket this would be thread controlled and either the thread is aborted or the client closes its end causing the read to return a -1 for number of bytes read.

// Threaded method
private void Receive()
{
    // Don't know how much of a buffer you need
    byte[] dataIn = byte[1000];
    while (acceptSocket.Connected)
    {
        // Exception handling so you either end the thread or keep processing data
        try
        {
            int bytesRead = acceptSocket.Read(dataIn);
            if (bytesRead != -1)
            {
                // Process your data
            }
            else
            {
                // -1 Bytes read should indicate the client shutdown on their end
                break;
            }
        }
        catch(SocketException se)
        {
            // You could exit this loop depending on the SocketException
        }
        catch(ThreadAbortException tae)
        {
            // Exit the loop
        }
        catch (Exception e)
        {
            // Handle exception, but keep reading for data
        }
    }

    // You have to check in case the socket was disposed or was never successfully created
    if (acceptSocket != null)
    {
        acceptSocket.Close();
    }
}

// This is the stop method if you press your stop button
private void Stop()
{
    // Aborts your read thread and the socket should be closed in the read thread.  The read thread should have a ThreadState.Stopped if the while loop was gracefully ended and the socket has already been closed
    if (readThread != null && readThread.ThreadState != ThreadState.Stopped)
    {
        readThread.Abort();
    }
}

I think this is the basics of what I've done before. I'm sure there are "cleaner" ways of doing this now. This was years ago when I use to implement TCP client/server socket objects.

Hope this helps...

Upvotes: 1

Related Questions