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

c#异步套接字客户端/服务器挂起服务器响应,c#,sockets,asynchronous,client,server,C#,Sockets,Asynchronous,Client,Server,我一直在玩我在MSDN上找到的一些c#套接字代码(原始和),我遇到了一个我不理解的问题。首先,这是我的套接字服务器代码: using System; using System.Collections; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; namespace AsyncSocketServer

我一直在玩我在MSDN上找到的一些c#套接字代码(原始和),我遇到了一个我不理解的问题。首先,这是我的套接字服务器代码:

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();
        }
    }
}
从这个输出中可以看到,当服务器接收到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()的调用,其他什么都没有。这让我相信服务器没有正确地从客户端读取数据,尽管我不知道为什么。我遗漏了什么?

这并不能真正回答您的确切问题,但我可以建议一种替代方法吗?对我来说,线程更容易理解,代码看起来更干净:

服务器

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现在做的工作已成功处理 从服务器收到:的命令:我是线程3现在做的工作已成功处理 发送:我是线程1现在做工作 从服务器收到:命令:我是线程1,现在已成功处理DO WORK


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

如果服务器接收到0,它将关闭连接bytes@Ewan-你说得对。我在服务器上的ReadCallback()中注释掉了对socket.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 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();
     }
  }
}