简体   繁体   English

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

[英]c# asynchronous socket client/server hangs on server response

I've been playing with some c# socket code that I found at MSDN (original server code and client code ) and I've run into a problem that I don't understand. 我一直在玩我在MSDN中找到的一些c#套接字代码(原始服务器代码客户端代码 ),遇到了一个我不理解的问题。 First, here is my socket server 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();
        }
    }
}

And now for the client code: 现在为客户代码:

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

If I comment out the code in the client that receives the response back from the server as well as the code in the server that attempts to send the response to the client, then things appear to be working as you would expect (ie, the client connects to the server, sends data and the server receives the data properly). 如果我注释掉客户端中从服务器接收回响应的代码以及尝试将响应发送到客户端的服务器中的代码,那么事情似乎正在按您期望的方式工作(即,客户端连接到服务器,发送数据,服务器正确接收数据)。 When I uncomment these sections of the code, however, I'm seeing some behavior that I don't understand. 但是,当我取消注释代码的这些部分时,会看到一些我不理解的行为。 In this case, I see the client connect to the server and send data to it. 在这种情况下,我看到客户端连接到服务器并向其发送数据。 On the server side, the code appears to hang inside ReadCallback(). 在服务器端,代码似乎挂在ReadCallback()内部。 To better illustrate this, when the code sections I mentioned previously are commented out, I see this: 为了更好地说明这一点,当我前面提到的代码部分被注释掉时,我看到了:

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...

As you can see from this output, when the server receives the 100 bytes of client data, I see two calls to ReadCallback(). 从该输出中可以看到,当服务器接收到100字节的客户端数据时,我看到了两次对ReadCallback()的调用。 So now I uncomment the aforementioned code and run it again. 因此,现在我取消注释前面提到的代码,然后再次运行它。 This time, I see: 这次,我看到:

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

This time, my client sends 100 bytes of data to the server, sets the sendDone ManualResetEvent and then goes into ReceiveBytes(). 这次,我的客户端将100字节的数据发送到服务器,设置sendDone ManualResetEvent,然后进入ReceiveBytes()。 On the server side, I see a single call to ReadCallback() and nothing else. 在服务器端,我只看到一次对ReadCallback()的调用,而没有其他任何调用。 That leads me to believe that the server didn't properly finish reading the data from the client although I'm not sure why. 这使我相信服务器无法正确完成从客户端的数据读取,尽管我不确定为什么。 What am I missing? 我想念什么?

This doesn't really answer your exact question but may I suggest an alternate way to go about this? 这并不能真正回答您的确切问题,但是我可以建议一种替代方法来解决此问题吗? For me threads are a bit easier to understand and the code looks a bit cleaner: 对我来说,线程更容易理解,代码看起来更简洁:

Server 服务器

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

} }

Client: 客户:

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

Server output: Received from client: I am thread 1 now DO WORK Sending acknowledgement to client Received from client: I am thread 2 now DO WORK Sending acknowledgement to client Received from client: I am thread 3 now DO WORK Sending acknowledgement to client 服务器输出:从客户端收到:我现在是线程1向客户端发送确认消息从客户端接收:我现在是线程2在向客户端发送确认消息从客户端接收到:我现在是线程3正在发送确认消息到客户端

Client output: Sending: I am thread 2 now DO WORK Sending: I am thread 3 now DO WORK Received from server: Command of: I am thread 2 now DO WORK was processed successfully Received from server: Command of: I am thread 3 now DO WORK was processed successfully Sending: I am thread 1 now DO WORK Received from server: Command of: I am thread 1 now DO WORK was processed successfully 客户端输出:发送:我现在是线程2做工作发送:我现在是线程3做工作从服务器接收:命令:我现在是线程2成功处理了工作从服务器接收:命令我:我现在是线程3 DO WORK已成功处理发送:我现在是线程1 DO WORK从服务器收到:命令:I我现在是线程1 DO WORK已成功处理

You could also use thread.Join() to have them finish executing in order. 您也可以使用thread.Join()使它们按顺序完成执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM