Le client socket / serveur asynchrone c # se bloque sur la réponse du serveur

J’ai joué avec un code de socket c # trouvé sur MSDN ( code du serveur d’ origine et code client ) et j’ai rencontré un problème que je ne comprends pas. Tout d’abord, voici mon code de serveur de socket:

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 bytes = new List(); } public static ManualResetEvent allDone = new ManualResetEvent(false); private const ssortingng 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.ToSsortingng()); } 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()..."); // resortingeve 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  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.ToSsortingng()); } // 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.ToSsortingng()); } } static void Main(ssortingng[] args) { StartListening(); Console.ReadKey(); } } } 

Et maintenant pour le code client:

 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 bytes = new List(); } private const ssortingng 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.ToSsortingng()); } } private static void ConnectCallback(IAsyncResult ar) { try { // resortingeve 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.ToSsortingng()); // 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.ToSsortingng()); } } 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.ToSsortingng()); } } private static void ReceiveCallback(IAsyncResult ar) { Console.WriteLine("Inside ReceiveCallback()..."); try { // Resortingeve 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  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.ToSsortingng()); } // Signal that all bytes have been received receiveDone.Set(); } } catch (Exception e) { Console.WriteLine(e.ToSsortingng()); } } 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 { // resortingeve 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.ToSsortingng()); } } static void Main(ssortingng[] args) { StartClient(); } } } 

Si je commente le code dans le client qui reçoit la réponse du serveur ainsi que le code du serveur qui tente d’envoyer la réponse au client, alors les choses semblent fonctionner comme prévu (par exemple, le client se connecte au serveur, envoie des données et le serveur reçoit les données correctement). Lorsque je décomment ces sections du code, je constate cependant un comportement que je ne comprends pas. Dans ce cas, le client se connecte au serveur et lui envoie des données. Côté serveur, le code semble se bloquer dans ReadCallback (). Pour mieux illustrer cela, lorsque les sections de code que j’ai mentionnées précédemment sont commentées, je vois ceci:

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

Comme vous pouvez le voir sur cette sortie, lorsque le serveur reçoit les 100 octets de données client, je vois deux appels à ReadCallback (). Alors maintenant, je désinscris le code susmentionné et le relance. Cette fois, je vois:

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

Cette fois, mon client envoie 100 octets de données au serveur, définit sendRone ManualResetEvent, puis passe dans ReceiveBytes (). Du côté du serveur, je vois un seul appel à ReadCallback () et rien d’autre. Cela m’amène à croire que le serveur n’a pas terminé correctement la lecture des données du client, même si je ne sais pas pourquoi. Qu’est-ce que je rate?

Cela ne répond pas vraiment à votre question exacte, mais puis-je suggérer une autre façon de procéder? Pour moi, les threads sont un peu plus faciles à comprendre et le code est un peu plus propre:

Serveur

 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(ssortingng[] 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); ssortingng strReceived = System.Text.Encoding.ASCII.GetSsortingng(bytes, 0, bytesRecieved); Console.WriteLine("Received from client: " + strReceived); Console.WriteLine("Sending acknowledgement to client"); ssortingng 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(ssortingng[] 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 ssortingng command; public ClientWorkThread(ssortingng 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); ssortingng strReceived = System.Text.Encoding.ASCII.GetSsortingng(bytes, 0, bytesRecieved); Console.WriteLine("Received from server: " + strReceived); objSocket.Close(); } } } 

Sortie du serveur: Reçue du client: je suis le thread 1 maintenant DO WORK Envoi de l’accusé de réception au client Reçu du client: je suis le thread 2 maintenant

Sortie client: Envoi: Je suis le thread 2 maintenant DO WORK Envoi: Je suis le thread 3 maintenant DO WORK Reçu du serveur: Commande de: Je suis le thread 2 maintenant DO WORK a été traité avec succès Envoi: Je suis le thread 1 maintenant DO WORK Reçu du serveur: Commande de: Je suis le thread 1 maintenant DO WORK a été traité avec succès

Vous pouvez également utiliser thread.Join () pour les terminer dans l’ordre.