Peut TCP c# client de recevoir et d'envoyer en continu/consécutivement sans sommeil?
C'est à un certain degré de "bases de TCP" question, mais en même temps, je n'ai pas encore trouver une réponse convaincante d'ailleurs, et je crois que j'ai un ok/bon de comprendre les bases de TCP. Je ne suis pas sûr si la combinaison de questions (ou l'une des questions et pendant que j'y suis, la demande de confirmation d'un couple de points) est contre les règles. N'espère pas.
Je suis en train d'écrire un C# de la mise en œuvre d'un client TCP, qui communique avec une application existante contenant un serveur TCP (je n'ai pas accès à son code, donc pas de WCF). Comment puis-je connecter, envoyer et recevoir au besoin, comme de nouvelles infos entrent ou sortent, et en fin de compte se déconnecter. À l'aide de le MSDN code comme un exemple où ils la liste "Envoyer" et "Recevoir" des méthodes asynchrones (ou juste TcpClient), et en ignorant la connecter et déconnecter comme trivial, comment puis-je mieux d'aller sur la permanence de la vérification des nouveaux paquets reçus et en même temps envoyer si nécessaire?
J'ai d'abord utilisé TCPClient et GetStream(), et le code msdn semble encore besoin de la boucle et de sommeil décrit dans un peu (contre-intuitivement), où j'ai exécuter la méthode de réception dans une boucle dans un thread séparé avec un sleep(10) millisecondes, et de l'Envoyer dans la main (ou troisième) thread en tant que de besoin. Cela me permet de m'envoyer l'amende, et la méthode de réception efficacement des sondages, à intervalles réguliers, afin de trouver de nouveaux paquets. Les paquets reçus sont ensuite ajoutés à la file d'attente.
Est-ce vraiment la meilleure solution? Ne devrait-il pas être un DataAvailable événement équivalent (ou quelque chose qui m'échappe dans le code msdn) qui nous permet de recevoir de si, et seulement si, il existe de nouvelles données sont disponibles?
Comme une réflexion après coup, j'ai remarqué que le support puisse être coupé de l'autre côté, sans que le client prend connaissance jusqu'à la prochaine bâclé envoyer. Pour clarifier puis, le client est tenu d'envoyer régulièrement des connexions actives (et de recevoir n'est pas suffisant, envoyer uniquement) afin de déterminer si le socket est toujours en vie. Et la fréquence de la keepalive détermine combien de temps je sais que le lien est en bas. Est-ce exact? J'ai essayé de Sondage, socket.connecté etc seulement de découvrir pourquoi chacun n'aident pas.
Enfin, pour confirmer (je crois pas mais bon de s'assurer), dans le scénario ci-dessus de l'envoi à la demande et de la réception si tcpclient.DataAvailable toutes les dix secondes, peut-il y avoir une perte de données si l'envoi et la réception en même temps? Si dans le même temps, je reçois j'essaie de l'envoyer sera un échec, écraser l'autre ou de tout autre comportement indésirable?
- Il est le TCPListener ainsi en permanence à l'écoute pour les connexions.
- recv blocs jusqu'à ce qu'il obtient des données, vous n'avez pas besoin de sommeil pour elle. Si vous voulez plus d'event driven trucs rechercher des sockets asynchrones. IO ports d'achèvement et de ces.
- Avez-vous utilisé BeginReceive que msdn exemple? Je pense que vous devriez lire sur la façon dont cela fonctionne. Ne asynchrone et qui est ce que vous cherchez.
- Ok, donc BeginReceive est non bloquant et fait exactement ce que je voulais... Mais pour TcpClient j'aurais besoin de sommeil. Va BeginReceive travailler en tandem avec envoyer à partir d'un autre thread?
- "pour TcpClient j'aurais besoin de sommeil" -- non. Pour
TcpClient
, en supposant que vous n'allez pas utiliser le sous-jacentClient
socket (et donc l'accès à tous de la même async I/O commeBeginReceive()
), vous appeler plutôtGetStream()
, et l'utilisation d'e/S asynchrone là, commeBeginRead()
ou maintenantReadAsync()
.
Vous devez vous connecter pour publier un commentaire.
Il n'y a rien de mal nécessairement avec le groupement de questions ensemble, mais il n'est de répondre à la question plus difficile... 🙂
L'article MSDN vous lié montre comment faire un seul et fait de la communication TCP, qui est, peut-on envoyer et recevoir. Vous remarquerez également qu'il utilise le
Socket
classe directement là où la plupart des gens, y compris moi-même, suggère d'utiliser leTcpClient
classe à la place. Vous pouvez toujours obtenir le sous-jacentSocket
via leClient
bien si vous avez besoin de configurer un certain socket par exemple (p. ex.,SetSocketOption()
).L'autre aspect de l'exemple à noter est que, bien qu'il utilise des threads pour exécuter le
AsyncCallback
délégués pour les deuxBeginSend()
etBeginReceive()
, il s'agit essentiellement d'un single-threaded exemple, en raison de la façon dont le ManualResetEvent objets sont utilisés. En cas de récidive de l'échange entre un client et un serveur, ce n'est pas ce que vous voulez.Très bien, alors vous voulez utiliser
TcpClient
. Connexion au serveur (par exemple,TcpListener
) doit être simple d'utilisationConnect()
si vous voulez une opération de blocage ouBeginConnect()
si vous voulez un non-opération de blocage. Une fois que la connexion est d'établir, d'utiliser leGetStream()
méthode pour obtenir leNetworkStream
objet à utiliser pour la lecture et l'écriture. Utiliser leRead()
/Write()
opérations de blocage I/O et leBeginRead()
/méthodes beginwrite()
opérations pour les non-blocage I/O. a Noter que leBeginRead()
etBeginWrite()
utiliser le mêmeAsyncCallback
mécanisme employé par leBeginReceive()
etBeginSend()
méthodes de laSocket
classe.L'une des principales choses à noter à ce point, est ce petit texte de présentation dans la documentation MSDN pour
NetworkStream
:En bref, parce que vous avez l'intention de lire et écrire à partir de la même
TcpClient
exemple, vous aurez besoin de deux fils pour le faire. À l'aide de threads séparés veillera à ce qu'aucune donnée n'est perdue lors de la réception de données en même temps quelqu'un essaie d'envoyer. La manière dont j'ai abordé ce problème dans mes projets est de créer un objet de niveau supérieur, direClient
, qui enveloppe leTcpClient
et de ses sous-jacentNetworkStream
. Cette classe crée et gère des deuxThread
objets, en les passant laNetworkStream
objet à chaque cours de construction. Le premier thread est leSender
fil. Tous ceux qui veulent envoyer des données fait par l'intermédiaire d'un publicSendData()
méthode sur laClient
, qui achemine les données vers leSender
pour la transmission. Le deuxième thread est leReceiver
fil. Ce fil à la publication de toutes les données reçues des parties intéressées par l'intermédiaire d'un événement public exposés par leClient
. Il ressemble à quelque chose comme ceci:Client.cs
Client.Le récepteur.cs
Client.Expéditeur.cs
Avis qu'il s'agit de trois .cs fichiers, mais de définir les différents aspects de la même
Client
classe. J'utilise Visual Studio astuce décrite ici à nid respectifsReceiver
etSender
fichiers en vertu de laClient
fichier. En un mot, c'est la façon dont je le fais.Concernant la
NetworkStream.DataAvailable
/Thread.Sleep()
question. Je suis d'accord qu'un événement pourrait être sympa, mais vous pouvez l'atteindre efficacement à l'aide de laRead()
méthode en combinaison avec une infinieReadTimeout
. Cela n'aura aucun impact négatif sur le reste de votre application (par exemple, l'INTERFACE utilisateur), car il s'exécute dans son propre thread. Toutefois, cela complique la fermeture du thread (par exemple, lorsque l'application se ferme), de sorte que vous voudrez probablement utiliser quelque chose de plus raisonnable, disons 10 millisecondes. Mais alors, vous êtes de retour dans les bureaux de vote, qui est ce que nous essayons d'éviter en premier lieu. Voici comment je le fais, avec des commentaires pour plus d'explications:Comme à présent comme "keepalive" sont concernés, il n'est malheureusement pas un moyen de contourner le problème de savoir quand l'autre côté n'a pas quitté la connexion silencieusement à l'exception d'essayer d'envoyer des données. Dans mon cas, depuis que je contrôle à la fois l'envoi et la réception des côtés, j'ai ajouté un petit
KeepAlive
message (8 octets) de mon protocole. C'est envoyé toutes les cinq secondes des deux côtés de la connexion TCP à moins que d'autres données est déjà en cours d'envoi.Je pense que j'ai répondu à toutes les facettes que vous avez touché. J'espère que vous trouverez ce utile.
DataAvailable
, en consacrant des threads pour les I/O, et l'utilisation explicite des messages keep-alive dans le protocole plutôt que d'utiliser le keep-alive option de socket, est l'un des plus élevés-ont voté exemples sur un Débordement de Pile. Bon réseau de code évitera toutes ces techniques, et utiliser à la place le très évolutif des Api asynchrones disponibles dans .NET. Surtout dans moderne C# avecasync
/await
, là où il est rendu bien plus facile (même si c'était toujours intéressant et de qualité supérieure à l'approche présentée ici).