BigDevJames
BigDevJames

Reputation: 2684

Asynchronous socket Server C#, how to get data from AsyncCallback

I have been trying to learn to use asynchronous sockets, and I'm sure my question is incredibly simple, but I have been having a really hard time finding a solution for it. I'm going to start from the code provided on MSDN at for Asynchronous Server and Asynchronous Client. I am following how the code works, except the one big question: How do I get the string the client sends back into the main function of the program? I see where the string is fully formed in the ReadCallback() function.

The question is how do I get the contents of the string content back to Main()? I put a few comments in to try and clarify what I am trying to get to where. Thank you in advance for your help.

Asynchronous Server:

using System;  
using System.Net;  
using System.Net.Sockets;  
using System.Text;  
using System.Threading;  

// State object for reading client data asynchronously  
public class StateObject {  
    // 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();    
}  

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

    public AsynchronousSocketListener() {  
    }  

    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  
        // running the listener is "host.contoso.com".  
        IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());  
        IPAddress ipAddress = ipHostInfo.AddressList[0];  
        IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);  

        // Create a TCP/IP socket.  
        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 );  

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

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

        Console.WriteLine("\nPress ENTER to continue...");  
        Console.Read();  

    }  

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

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

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

    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;  
        Socket 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) {  
                // 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 );  
                // Echo the data back to the client. 
                // AT THIS POINT content SHOULD HAVE THE STRING SENT 
                Send(handler, content);  
            } else {  
                // Not all data received. Get more.  
                handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,  
                new AsyncCallback(ReadCallback), state);  
            }  
        }  
    }  

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

        // Begin sending the data to the remote device.  
        handler.BeginSend(byteData, 0, byteData.Length, 0,  
            new AsyncCallback(SendCallback), 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);  

            handler.Shutdown(SocketShutdown.Both);  
            handler.Close();  

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

    public static int Main(String[] args) {  
        StartListening();  
        // I want to make string here that has the result from ReadCallback so I can then perform other logic on the string.
        return 0;  
    }  
} 

Upvotes: 3

Views: 7248

Answers (1)

Mong Zhu
Mong Zhu

Reputation: 23732

Your followed the example quite right. You just need to wait for the input. Put a Console.ReadLine(); before the return statement:

public static int Main(String[] args) 
{  
    StartListening();  
    // I want to make string here that has the result from ReadCallback so I can then perform other logic on the string.

    Console.ReadLine();
    return 0;  
} 

If you want to print out the input. Just use Console.WriteLine() after you decoded the received bytesin the ReadCallback method:

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();  

    // print the stuff to the console
    Console.WriteLine(content);

If you want to have the content and do something with it you can declare it as a static class variable and you will be able to access it in the main method:

public class AsynchronousSocketListener 
{
    public static string content = "";


public static int Main(String[] args) 
{  
    StartListening();  
    // I want to make string here that has the result from ReadCallback so I can then perform other logic on the string.

    Console.ReadLine();

    // wait until the message has arrive and press enter to jump to this line
    Console.WriteLine("Now I can do what ever I want with the incoming message: " + content);
    // just to be able to read it one more time before the program ends ;)
    Console.ReadLine();
    return 0;  
} 

Of course you have to remove the declaration from the ReadCallback.

You have to be aware that it is asynchronous and hence you will have to wait for the message to arrive. But you can see it in the console if you print it there. The rest is up to you

Upvotes: 2

Related Questions