Voici donc une réponse qui vous permettra de démarrer - ce qui est plus de niveau débutant que mon blog post.
.Net a un modèle asynchrone qui tourne autour d'un appel Begin * et End *. Par exemple - BeginReceive
et EndReceive
. Ils ont presque toujours leur équivalent non-asynchrone (dans ce cas Receive
); et atteindre le même objectif. La chose la plus importante à retenir est que les socket font plus que juste faire l'appel asynchrone - ils exposent quelque chose appelé IOCP (IO Completion Ports, Linux/Mono a ces deux mais j'ai oublié le nom) qui est extrêmement important utiliser sur un serveur; Le cœur de ce que fait IOCP est que votre application ne consomme pas de thread pendant qu'elle attend des données.
Comment utiliser le modèle Début/Fin
Chaque méthode Begin * aura exactement deux arguments plus en comparisson à son homologue non-async.Le premier est un AsyncCallback, le second est un objet. Ce que ces deux signifient, c'est "voici une méthode à appeler quand vous avez terminé" et "voici quelques données dont j'ai besoin à l'intérieur de cette méthode". La méthode qui est appelée a toujours la même signature, dans cette méthode vous appelez la contrepartie End * pour obtenir ce qui aurait été le résultat si vous l'aviez fait de manière synchrone. Ainsi, par exemple:
private void BeginReceiveBuffer()
{
_socket.BeginReceive(buffer, 0, buffer.Length, BufferEndReceive, buffer);
}
private void EndReceiveBuffer(IAsyncResult state)
{
var buffer = (byte[])state.AsyncState; // This is the last parameter.
var length = _socket.EndReceive(state); // This is the return value of the method call.
DataReceived(buffer, 0, length); // Do something with the data.
}
Qu'est-ce qui se passe ici est .Net commence en attente pour les données de la prise, dès qu'il reçoit les données qu'il appelle EndReceiveBuffer
et passe à travers les « données personnalisées » (dans ce cas buffer
) pour le via state.AsyncResult
. Lorsque vous appelez EndReceive
, il vous restituera la longueur des données reçues (ou lancera une exception si quelque chose a échoué).
meilleur modèle pour douilles
Ce formulaire vous donnera la gestion des erreurs centrale - il peut être utilisé partout où le motif async enroule un flux comme « chose » (par exemple TCP arrive dans l'ordre qu'il a été envoyé , donc il pourrait être vu comme un objet Stream
).
private Socket _socket;
private ArraySegment<byte> _buffer;
public void StartReceive()
{
ReceiveAsyncLoop(null);
}
// Note that this method is not guaranteed (in fact
// unlikely) to remain on a single thread across
// async invocations.
private void ReceiveAsyncLoop(IAsyncResult result)
{
try
{
// This only gets called once - via StartReceive()
if (result != null)
{
int numberOfBytesRead = _socket.EndReceive(result);
if(numberOfBytesRead == 0)
{
OnDisconnected(null); // 'null' being the exception. The client disconnected normally in this case.
return;
}
var newSegment = new ArraySegment<byte>(_buffer.Array, _buffer.Offset, numberOfBytesRead);
// This method needs its own error handling. Don't let it throw exceptions unless you
// want to disconnect the client.
OnDataReceived(newSegment);
}
// Because of this method call, it's as though we are creating a 'while' loop.
// However this is called an async loop, but you can see it the same way.
_socket.BeginReceive(_buffer.Array, _buffer.Offset, _buffer.Count, SocketFlags.None, ReceiveAsyncLoop, null);
}
catch (Exception ex)
{
// Socket error handling here.
}
}
accepte les connexions multiples
ce que vous faites en général est d'écrire une classe qui contient votre prise etc. (ainsi que votre boucle async) et créer un pour chaque client. Ainsi, par exemple:
public class InboundConnection
{
private Socket _socket;
private ArraySegment<byte> _buffer;
public InboundConnection(Socket clientSocket)
{
_socket = clientSocket;
_buffer = new ArraySegment<byte>(new byte[4096], 0, 4096);
StartReceive(); // Start the read async loop.
}
private void StartReceive() ...
private void ReceiveAsyncLoop() ...
private void OnDataReceived() ...
}
doit être suivi chaque connexion client par votre classe de serveur (de sorte que vous pouvez les déconnecter proprement lorsque le serveur arrête, ainsi que la recherche/les consulter).
Plug sans vergogne: http://jonathan.dickinsons.co.za/blog/2011/02/net-sockets-and-you/ - il touche brièvement la boucle async; et contient une implémentation réelle (vous ne devriez pas utiliser 'ThreadPool' comme suggéré par @Jalal). –