如何在C#中调用socket的回调方法?

时间:2014-03-21 09:51:08

标签: c# sockets tcp

我想知道是否可以调用回调方法?我正在创建一个项目,它连接套接字,接收和发送数据24小时。这里我使用BeginReceive()和EndReceive()方法。

以下是我的代码:

public void Receive(Socket client)
{
    StateObject state = new StateObject();
    state.workSocket = client;

    try
    {
        if (m_clientSocket.Connected)
        {
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
        }
        else
        {
            Connect();
        }
    }
    catch (SocketException se)
    {
        logstr = se.Message;
        write_log(logstr, "Receive", "Receive");
    }
}

public void ReceiveCallback(IAsyncResult ar)
{
    StateObject state = (StateObject)ar.AsyncState;
    Socket client = state.workSocket;
    string receiveData = "";
    string sendData = "";
    int bytesRead = client.EndReceive(ar);

    if (bytesRead > 0)
    {
        state.sb.Append(System.Text.Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
        client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);

        receiveData = state.sb.ToString();

        this.IsBulk.Items.Insert(0, receiveData);
        sendData = getReply(receiveData);
        write_log(DateTime.Now.ToString() + " : " + receiveData, "bytesRead", "bytesRead");

        try
        {
            Object objData = sendData;
            byte[] byData = System.Text.Encoding.ASCII.GetBytes(objData.ToString());

            if (m_clientSocket != null)
            {
                m_clientSocket.Send(byData);
            }

            write_log(DateTime.Now.ToString() + " : " + sendData, "sendData", "sendData");
        }
        catch (SocketException se)
        {
            logstr = se.Message;
            write_log(logstr, "WaitForData", "waitfordata");
        }
    }
    else
    {
        receiveData = state.sb.ToString();

        if (!string.IsNullOrEmpty(receiveData))
        {
            write_log(DateTime.Now.ToString() + " : " + receiveData, "receiveData2", "receiveData2");
        }
    }
}

但是当我逐行调试时,我的光标不会转到回调方法ReceiveCallback()。所以,我很困惑它是否正常或我做错了什么?如果我犯了一些错误,那么我想知道如何从另一个函数调用ReceiveCallback()方法。任何帮助将不胜感激。谢谢

2 个答案:

答案 0 :(得分:1)

Socket.BeginReceive()方法中,只有定义将数据发送到套接字时将调用的回调是什么。

因此,如果您在Receive()中逐行进行,那么您不必跳转到ReceiveCallback()方法是正常的。

但是,如果您还在ReceiveCallback()中放置一个断点,并开始向套接字发送数据,您将看到它按预期调用。

答案 1 :(得分:1)

正如您所要求的那样,这里有两个小例子,一个用于TcpClient,一个用于TcpServer。

一个小TcpServer示例:

namespace TcpServer
{
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;

    /// <summary>
    /// Contains possible exit codes for the application.
    /// </summary>
    public enum ApplicationExitCode
    {
        /// <summary>
        /// Represents an exit code which hint's that there was an abnormal program termination.
        /// </summary>
        Error = 1,

        /// <summary>
        /// Represents an exit code which hint's that there was no abnormal program termination.
        /// </summary>
        OK = 0
    }

    /// <summary>
    /// Represents out Program class.
    /// </summary>
    public class Server
    {
        /// <summary>
        /// Represents the port on which the server will try to listen.
        /// </summary>
        private const int SERVERPORT = 12345;

        /// <summary>
        /// Represents the threads that handle the client connections.
        /// </summary>
        private static List<Thread> clientThreads = new List<Thread>();

        /// <summary>
        /// The entry point of our application.
        /// </summary>
        /// <param name="args">The command line arguments.</param>
        public static void Main(string[] args)
        {
            // Establish a tcpListener on any network interface at port SERVERPORT
            IPEndPoint localEndpoint = new IPEndPoint(IPAddress.Any, SERVERPORT);
            TcpListener listener = new TcpListener(localEndpoint);

            try
            {
                // Try to start the listener which will try to bind to the socket.
                listener.Start();
            }
            catch (SocketException socketEx)
            {
                Console.WriteLine("Server: Unable to establish listener at {0}:{1}", localEndpoint.Address.ToString(), localEndpoint.Port.ToString());
                Console.WriteLine(socketEx.Message);
                Environment.Exit((int)ApplicationExitCode.Error);
            }

            // Print status information.
            Console.WriteLine("Server: You can terminate the application by pressing the ESC-key.");
            Console.WriteLine("Server: Listener at {0}:{1} established, waiting for incomming connections...", localEndpoint.Address.ToString(), localEndpoint.Port.ToString());

            bool listenForClients = true; // Used for controlling the listener loop.
            int connectionID = 0; // Used for distinguishing the connections in the console output.

            do
            {
                // Check for user input.
                if (Console.KeyAvailable)
                {
                    listenForClients = Console.ReadKey(true).Key != ConsoleKey.Escape;
                }

                // Check for new client.
                if (listener.Pending())
                {
                    // Create a new thread for the connecting client.
                    Thread t = new Thread(new ParameterizedThreadStart(ClientWorker));

                    // Set the thread as background thread (which would/could terminate with the main thread - we don't want that).
                    t.IsBackground = true;

                    // Set the thread name to the connectionID (which is a number increasing with each new client).
                    t.Name = (connectionID++).ToString();

                    // Start the thread and pass a reference to the new client object which we receive from AcceptTcpClient().
                    t.Start((object)listener.AcceptTcpClient());

                    // Add the thread to the list so we can terminate it later.
                    clientThreads.Add(t);
                }
                else
                {
                    // Sleep - I like that ;-)
                    Thread.Sleep(100);
                }
            }
            while (listenForClients);

            // Stop the listener.
            listener.Stop();

            // Print status message.
            Console.WriteLine("Server: Sending abort request to all threads.");

            // Send abort request to all client threads.
            foreach (Thread t in clientThreads)
            {
                t.Abort();
            }

            // Print status message.
            Console.WriteLine("Server: Waiting for all threads to terminate.");

            // Wait for all client threads to really terminate.
            foreach (Thread t in clientThreads)
            {
                t.Join();
            }

            // Print status message.
            Console.WriteLine("Server: Exiting application.");

            // Exit the application.
            Environment.Exit((int)ApplicationExitCode.OK);
        }

        /// <summary>
        /// Represents the client thread which is started for each new connection.
        /// </summary>
        /// <param name="data">The tcpClient object.</param>
        private static void ClientWorker(object data)
        {
            TcpClient tcpClient = (TcpClient)data;
            NetworkStream ns;
            string threadName = Thread.CurrentThread.Name;
            bool processData = true;

            Console.WriteLine("Thread {0}: Started.", threadName);

            // Try to fetch the network stream
            try
            {
                ns = tcpClient.GetStream();
            }
            catch
            {
                Console.WriteLine("Thread {0}: Unable to fetch the network stream, exiting thread.", threadName);
                return;
            }

            // Print cool message.
            Console.WriteLine("Thread {0}: Network stream fetched.", threadName);

            try
            {
                byte[] receiveBuffer = new byte[1024];
                byte[] sendBuffer;
                int bytesRead = 0;
                string message;

                while (processData)
                {
                    // If data is available on the stream
                    if (ns.DataAvailable)
                    {
                        // Read data from the stream.
                        bytesRead = ns.Read(receiveBuffer, 0, receiveBuffer.Length);

                        // Write the received number of bytes.
                        Console.WriteLine("Thread {0}: Received {1} bytes.", threadName, bytesRead);

                        // Write the bytes (in hex format).
                        Console.Write("Thread {0}: ", threadName);

                        for (int i = 0; i < bytesRead; i++)
                        {
                            Console.Write("{0:X2} ", receiveBuffer[i]);
                        }

                        // "Decode" the data.
                        message = Encoding.ASCII.GetString(receiveBuffer, 0, bytesRead);
                        Console.WriteLine("\nThread {0}: Decoding data using ASCII table.", threadName);

                        // Write the decoded message.
                        Console.WriteLine("Thread {0}: {1}", threadName, message);

                        // Build the answer byte array.
                        sendBuffer = Encoding.ASCII.GetBytes("Hab's bekommen ;-)\r\n");

                        // Write the answer.
                        ns.Write(sendBuffer, 0, sendBuffer.Length);
                    }
                    else
                    {
                        Thread.Sleep(100);
                    }
                }
            }
            catch (ThreadAbortException)
            {
                // Print status message.
                Console.WriteLine("Thread {0}: Abort requested.", threadName);

                // Set loop condition.
                processData = false;

                // Reset abort request.
                Thread.ResetAbort();
            }
            catch (Exception generalEx)
            {
                Console.WriteLine("Thread {0}: Exception occured.", threadName);
                Console.WriteLine("Thread {0}: {1}", threadName, generalEx.Message);
            }
            finally
            {
                // If the network stream still exists.
                if (ns != null)
                {
                    // Flush the stream.
                    ns.Flush();

                    // Close the stream.
                    ns.Close();

                    // Dispose the stream.
                    ns.Dispose();
                }

                // If the tcpClient object still exists.
                if (tcpClient != null)
                {
                    // Close the client.
                    tcpClient.Close();
                }

                // Print status message.
                Console.WriteLine("Thread {0}: Stopping.", threadName);
            }
        }
    }
}

一个小TcpClient示例:

namespace TcpClient
{
    using System;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;

    /// <summary>
    /// Represents our Server class.
    /// </summary>
    public class Client
    {
        /// <summary>
        /// The entry point of our application.
        /// </summary>
        /// <param name="args">The command line arguments.</param>
        public static void Main(string[] args)
        {
            IPAddress ipAddress;
            IPEndPoint ipEndPoint;
            TcpClient tcpClient;
            NetworkStream ns = null;
            int port;

            // Let the user input the IP-Address.
            Console.Write("Bitte geben Sie die IPAdresse an: ");
            ipAddress = IPAddress.Parse(Console.ReadLine());

            // Let the user input the port number.
            Console.Write("Bitte geben Sie den Port an: ");
            port = int.Parse(Console.ReadLine());

            // Create a new IPEndPoint object.
            ipEndPoint = new IPEndPoint(ipAddress, port);

            // Create a new TcpClient object.
            tcpClient = new TcpClient();

            // Connect the client to the endpoint.
            tcpClient.Connect(ipEndPoint);

            // Try to fetch the network stream
            try
            {
                ns = tcpClient.GetStream();
            }
            catch
            {
                Console.WriteLine("Unable to fetch the network stream, exiting thread.");
                Environment.Exit(1);
            }

            // Print cool message.
            Console.WriteLine("Network stream fetched.");

            // Declare receive and send buffer and some other stuff.
            byte[] receiveBuffer = new byte[1024];
            byte[] sendBuffer;
            int bytesRead = 0;
            string message;
            bool processData = true;

            // Until someone types "exit"
            while (processData)
            {
                Console.Write("Please enter your message: ");

                message = Console.ReadLine();

                if (message.ToLower() == "exit")
                {
                    processData = false;
                    continue;
                }

                // Get bytes of the message.
                sendBuffer = Encoding.ASCII.GetBytes(message);

                // Write the data into the stream.
                ns.Write(sendBuffer, 0, sendBuffer.Length);

                // Read data from the stream.
                bytesRead = ns.Read(receiveBuffer, 0, receiveBuffer.Length);

                // Decode the data.
                message = Encoding.ASCII.GetString(receiveBuffer, 0, bytesRead);

                // Write it into the console window.
                Console.WriteLine(message);
            }

            ns.Flush();
            ns.Close();
            ns.Dispose();
            tcpClient.Close();
        }
    }
}

我希望它能以某种方式帮助你; - )