c#异步套接字客户端/服务器挂起服务器响应

时间:2015-04-15 12:57:23

标签: c# sockets asynchronous client server

我一直在使用我在MSDN上找到的一些c#套接字代码(原始server codeclient code)并且我遇到了一个我不会遇到的问题'明白。首先,这是我的套接字服务器代码:

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

namespace AsyncSocketServerTest
{
    class Program
    {
        public class StateObject
        {
            public Socket socket = null;
            public const int BufferSize = 1024;
            public byte[] buffer = new byte[BufferSize];
            public List<byte> bytes = new List<byte>();
        }

        public static ManualResetEvent allDone = new ManualResetEvent(false);

        private const string ipAdd = "127.0.0.1";

        public static void StartListening()
        {
            byte[] bytes = new byte[1024];

            IPAddress ipAddress = IPAddress.Parse(ipAdd);
            IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 25981);

            Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            try
            {
                listener.Bind(localEndPoint);
                listener.Listen(100);

                while (true)
                {
                    allDone.Reset();
                    listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
                    allDone.WaitOne();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }

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

        public static void AcceptCallback(IAsyncResult ar)
        {
            allDone.Set();

            Socket listener = (Socket)ar.AsyncState;
            Socket handler = listener.EndAccept(ar);

            StateObject state = new StateObject();
            state.socket = handler;
            handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
        }

        public static void ReadCallback(IAsyncResult ar)
        {
            Console.WriteLine("Inside ReadCallback()...");

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

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

            if (bytesRead > 0)
            {
                // there might be more data, so store the data received so far
                for (int bufferIndex = 0; bufferIndex < bytesRead; bufferIndex++)
                {
                    state.bytes.Add(state.buffer[bufferIndex]);
                }

                socket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
            }
            else
            {
                if (state.bytes.Count > 0)
                {
                    // All the data has been read from the client; display it on the console.
                    byte[] bytesReceived = state.bytes.ToArray();

                    Console.WriteLine("Received {0} bytes from client...", bytesReceived.Length.ToString());
                }

                // generate a 50 byte response to send back to the client
                Random r = new Random();
                byte[] responseToSend = new byte[50];
                r.NextBytes(responseToSend);

                // *** THIS APPEARS TO BE CAUSING A PROBLEM ***
                // send the response back to client
                SendBytes(socket, responseToSend);
                // ********************************************

                // edit - commented out; the socket shouldn't be closed before the response is sent back to the client asynchronously
                //socket.Close();
            }
        }

        private static void SendBytes(Socket client, byte[] bytesToSend)
        {
            client.BeginSend(bytesToSend, 0, bytesToSend.Length, 0, new AsyncCallback(SendCallback), client);
        }

        private static void SendCallback(IAsyncResult ar)
        {
            try
            {
                Socket handler = (Socket)ar.AsyncState;

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

        static void Main(string[] args)
        {
            StartListening();
            Console.ReadKey();
        }
    }
}

现在为客户端代码:

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

namespace AsyncSocketClientTest
{
    class Program
    {
        public class StateObject
        {
            public Socket socket = null;
            public const int BufferSize = 1024;
            public byte[] buffer = new byte[BufferSize];
            public List<byte> bytes = new List<byte>();
        }

        private const string ipAdd = "127.0.0.1";

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

        private static void StartClient()
        {
            try
            {
                IPAddress ipAddress = IPAddress.Parse(ipAdd);
                IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, 25981);

                Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                client.BeginConnect(remoteEndPoint, new AsyncCallback(ConnectCallback), client);
                connectDone.WaitOne();

                // generate 100 random bytes to send to the server
                Random r = new Random();
                byte[] buffer = new byte[100];
                r.NextBytes(buffer);

                // send data to the server
                SendBytes(client, buffer);
                sendDone.WaitOne();

                // *** THIS APPEARS TO BE CAUSING A PROBLEM ***
                // receive the response from the remote host
                ReceiveBytes(client);
                receiveDone.WaitOne();
                // ********************************************

                // release the socket
                client.Shutdown(SocketShutdown.Both);
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        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();
            }
            catch (SocketException sockEx)
            {
                // if the server isn't running, we're going to get a socket exception here...
                Console.WriteLine(sockEx.Message);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        private static void ReceiveBytes(Socket client)
        {
            Console.WriteLine("Inside ReceiveBytes()...");

            try
            {
                // create the state object
                StateObject state = new StateObject();
                state.socket = client;

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

        private static void ReceiveCallback(IAsyncResult ar)
        {
            Console.WriteLine("Inside ReceiveCallback()...");

            try
            {
                // Retrieve the state object and the client socket from the asynchronous state object
                StateObject state = (StateObject)ar.AsyncState;
                Socket client = state.socket;

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

                if (bytesRead > 0)
                {
                    // there might be more data, so store the data received so far
                    for (int bufferIndex = 0; bufferIndex < bytesRead; bufferIndex++)
                    {
                        state.bytes.Add(state.buffer[bufferIndex]);
                    }

                    client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
                }
                else
                {
                    if (state.bytes.Count > 0)
                    {
                        // All the data has been read from the client; display it on the console.
                        byte[] bytesReceived = state.bytes.ToArray();

                        Console.WriteLine("Read {0} bytes from socket...", bytesReceived.Length.ToString());
                    }

                    // Signal that all bytes have been received
                    receiveDone.Set();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        private static void SendBytes(Socket client, byte[] bytesToSend)
        {
            // Begin sending the data to the remote device
            client.BeginSend(bytesToSend, 0, bytesToSend.Length, 0, new AsyncCallback(SendCallback), client);
        }

        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();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        static void Main(string[] args)
        {
            StartClient();
        }
    }
}

如果我注释掉客户端中从服务器接收响应的代码以及尝试将响应发送到客户端的服务器中的代码,那么事情似乎正如您所期望的那样工作(即,客户端连接到服务器,发送数据,服务器正确接收数据)。但是,当我取消注释代码的这些部分时,我会看到一些我不理解的行为。在这种情况下,我看到客户端连接到服务器并向其发送数据。在服务器端,代码似乎挂在ReadCallback()中。为了更好地说明这一点,当我之前提到的代码部分被注释掉时,我看到了:

Client output:

Socket connected to 127.0.0.1:25981
Sent 100 bytes to server.


Server output:

Waiting for a connection...
Waiting for a connection...
Inside ReadCallback()...
Inside ReadCallback()...
Received 100 bytes from client...

从这个输出可以看出,当服务器收到100字节的客户端数据时,我看到两次调用ReadCallback()。所以现在我取消注释上述代码并再次运行它。这一次,我看到了:

Client output:

Socket connected to 127.0.0.1:25981
Sent 100 bytes to server.
Inside ReceiveBytes()...


Server output:

Waiting for a connection...
Waiting for a connection...
Inside ReadCallback()...

这次,我的客户端向服务器发送100字节的数据,设置sendDone ManualResetEvent,然后进入ReceiveBytes()。在服务器端,我看到一个对ReadCallback()的调用,没有别的。这让我相信服务器没有正确地完成从客户端读取数据,尽管我不确定原因。我错过了什么?

1 个答案:

答案 0 :(得分:1)

这并没有真正回答您的确切问题,但我可以建议另一种方法来解决这个问题吗?对我来说,线程更容易理解,代码看起来更清晰:

服务器

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 ConsoleApplication2 {
class Program {
  static void Main(string[] args) {
     ServerWorkThread objThread = new ServerWorkThread();
     while(true) {
        objThread.HandleConnection(objThread.mySocket.Accept());
     }
  }
}

public class ServerWorkThread {
     public Socket mySocket;
     public ServerWorkThread() {
        IPEndPoint objEnpoint = new IPEndPoint(IPAddress.Parse("***.***.***.***"), 8888);
        mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        mySocket.Bind(objEnpoint);
        mySocket.Listen(100);
     }

     public void HandleConnection(Socket iIncomingSocket) {
        Thread worker = new Thread(this.RecieveAndSend);
        worker.Start(iIncomingSocket);
        worker.Join();
     }

     public void RecieveAndSend(object iIncoming) {
        Socket objSocket = (Socket)iIncoming;
        byte[] bytes = new byte[1024];

        int bytesRecieved = objSocket.Receive(bytes);
        string strReceived = System.Text.Encoding.ASCII.GetString(bytes, 0, bytesRecieved);
        Console.WriteLine("Received from client: " + strReceived);

        Console.WriteLine("Sending acknowledgement to client");
        string strSend = ("Command of: " + strReceived + " was processed successfully");
        objSocket.Send(System.Text.Encoding.ASCII.GetBytes(strSend));

        objSocket.Close();
     }
  }

}

客户端:

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 {
class Program {
  static void Main(string[] args) {
     ClientWorkThread thread1 = new ClientWorkThread("I am thread 1");
     thread1.SendCommand();
     ClientWorkThread thread2 = new ClientWorkThread("I am thread 2");
     thread2.SendCommand();
     ClientWorkThread thread3 = new ClientWorkThread("I am thread 3");
     thread3.SendCommand();
     Console.Read();
  }
}


  public class ClientWorkThread {

     private Socket pSocket;
     private string command;
     public ClientWorkThread(string iCommand) {
        IPEndPoint objEnpoint = new IPEndPoint(IPAddress.Parse("***.***.***.***"), 8888);
        pSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        pSocket.Connect(objEnpoint);
        command = iCommand;
     }

     public void SendCommand() {
        Thread worker = new Thread(this.Send);
        worker.Start(pSocket);

     }

     public void Send(object iSending) {
        Socket objSocket = (Socket)iSending;
        objSocket.Send(System.Text.Encoding.ASCII.GetBytes(command + " now DO WORK "));
        Console.WriteLine("Sending: " + command + " now DO WORK ");
        byte[] bytes = new byte[1024];
        int bytesRecieved = objSocket.Receive(bytes);
        string strReceived = System.Text.Encoding.ASCII.GetString(bytes, 0, bytesRecieved);
        Console.WriteLine("Received from server: " + strReceived);
        objSocket.Close();
     }
  }
}

服务器输出:     从客户收到:我现在是线程1工作     向客户发送确认     从客户收到:我现在是线程2工作     向客户发送确认     从客户收到:我现在是线程3工作     向客户发送确认

客户输出:     发送:我现在是线程2工作     发送:我现在是第3个线程    从服务器收到:命令:我现在是线程2 DO WORK已成功处理     从服务器收到:命令:我现在是线程3 DO WORK已成功处理     发送:我现在是线程1工作     从服务器收到:命令:我现在是线程1 DO WORK已成功处理

你也可以使用thread.Join()让它们按顺序完成执行。