TCP Connexion Client
J'ai une application que j'ai écrit pour mon application distribuée dans toute l'entreprise pour envoyer des données à moi par le biais de notre Windows 2003 server (IIS 6.0). Petits messages texte à passer à travers, mais plus de messages contenant des données (environ 20 KO) ne sont pas obtenir à travers.
J'ai mis le tampon d'octets pour le Client TCP de la taille de la mémoire tampon. J'ai remarqué que mes données a été reçu sur le serveur; toutefois, il ne boucle à travers la réception de la routine une fois, et mon gros fichiers étaient toujours exactement la taille de la taille de la mémoire tampon, ou 8 KO sur notre serveur. En d'autres termes, mon code ne fait que grâce à une boucle avant que le serveur ferme la connexion de socket.
Penser qu'il y a peut-être un problème de remplissage de la mémoire tampon entier, j'ai essayé de limiter ma lecture/écriture à tout juste 1 KO mais cela n'a abouti à notre serveur fermeture de la socket après la réception de 1 KO avant la fermeture de la connexion.
J'envoie le serveur de message d'erreur au client afin que je puisse la voir. Le message d'erreur que je reçois de la part du client est:
“Impossible d'écrire des données pour le transport
connexion: Une connexion établie
a été abandonnée par le logiciel dans votre
la machine hôte.”
J'ai mis à jour mon serveur de l'application, de sorte que le sous-jacent Socket TCP serait d'utiliser “garder avie” avec cette ligne:
client.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true);
Maintenant, chaque fois que je tente d'envoyer un message, le client reçoit le message d'erreur:
“Impossible d'écrire des données pour le transport
connexion: Une connexion existante a
dû être fermée par l'hôte distant.”
Notre Administrateur Réseau m'a dit qu'il n'a pas un pare-feu ou tout les ports bloqués sur notre serveur interne.
Googler les erreurs, j'ai trouvé les messages suggérant les gens essaient de telnet sur le serveur. J'ai utilisé leurs directions de telnet sur le serveur, mais je ne suis pas sûr de ce que pour faire de la réponse:
C:> Bienvenue dans Microsoft telnet
Client TelnetCaractère d'échappement est "CTRL"+"]’
Microsoft Telnet> ouvrir cpapp 500
La connexion À cpapp...
C'est tout ce que je reçois. Je n'ai jamais eu une erreur, et Microsoft Telnet de l'écran de changement “Appuyez sur une touche pour continuer...” – je suppose que non, mais mon code est en quelque sorte en mesure de se connecter.
J'ai essayé d'autres ports dans le code et par le biais de Telnet, y compris 25, 80 et 8080. Telnet des coups de pied dans le port 25, mais ma demande semble à la lecture de la première boucle de n'importe quel port je lui dis de s'exécuter.
Voici mon code qui s'exécute sur les clients:
int sendUsingTcp(string location) {
string result = string.Empty;
try {
using (FileStream fs = new FileStream(location, FileMode.Open, FileAccess.Read)) {
using (TcpClient client = new TcpClient(GetHostIP, CpAppDatabase.ServerPortNumber)) {
byte[] riteBuf = new byte[client.SendBufferSize];
byte[] readBuf = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream()) {
if ((ns.CanRead == true) && (ns.CanWrite == true)) {
int len;
string AOK = string.Empty;
do {
len = fs.Read(riteBuf, 0, riteBuf.Length);
ns.Write(riteBuf, 0, len);
int nsRsvp = ns.Read(readBuf, 0, readBuf.Length);
AOK = Encoding.ASCII.GetString(readBuf, 0, nsRsvp);
} while ((len == riteBuf.Length) && (-1 < AOK.IndexOf("AOK")));
result = AOK;
return 1;
}
return 0;
}
}
}
} catch (Exception err) {
Logger.LogError("Send()", err);
MessageBox.Show(err.Message, "Message Failed", MessageBoxButtons.OK, MessageBoxIcon.Hand, 0);
return -1;
}
}
Voici mon code qui s'exécute sur le serveur:
SvrForm.Server = new TcpListener(IPAddress.Any, CpAppDatabase.ServerPortNumber);
void Worker_Engine(object sender, DoWorkEventArgs e) {
BackgroundWorker worker = sender as BackgroundWorker;
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Application.CompanyName);
if (Directory.Exists(path) == false) Directory.CreateDirectory(path);
Thread.Sleep(0);
string eMsg = string.Empty;
try {
SvrForm.Server.Start();
do {
using (TcpClient client = SvrForm.Server.AcceptTcpClient()) { //waits until data is avaiable
if (worker.CancellationPending == true) return;
client.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true);
string location = Path.Combine(path, string.Format("Acp{0:yyyyMMddHHmmssff}.bin", DateTime.Now));
byte[] buf = new byte[client.ReceiveBufferSize];
try {
using (NetworkStream ns = client.GetStream()) {
if ((ns.CanRead == true) && (ns.CanWrite == true)) {
try {
int len;
byte[] AOK = Encoding.ASCII.GetBytes("AOK");
using (FileStream fs = new FileStream(location, FileMode.Create, FileAccess.Write)) {
do {
len = ns.Read(buf, 0, client.ReceiveBufferSize);
fs.Write(buf, 0, len);
ns.Write(AOK, 0, AOK.Length);
} while ((0 < len) && (ns.DataAvailable == true));
}
byte[] okBuf = Encoding.ASCII.GetBytes("Message Received on Server");
ns.Write(okBuf, 0, okBuf.Length);
} catch (Exception err) {
Global.LogError("ServerForm.cs - Worker_Engine(DoWorkEvent)", err);
byte[] errBuf = Encoding.ASCII.GetBytes(err.Message);
ns.Write(errBuf, 0, errBuf.Length);
}
}
}
}
worker.ReportProgress(1, location);
}
} while (worker.CancellationPending == false);
} catch (SocketException) {
//See MSDN: Windows Sockets V2 API Error Code Documentation for detailed description of error code
e.Cancel = true;
} catch (Exception err) {
eMsg = "Worker General Error:\r\n" + err.Message;
e.Cancel = true;
e.Result = err;
} finally {
SvrForm.Server.Stop();
}
}
Pourquoi ne pas mon application continuer la lecture à partir de la Client TCP? Ai-je négligé de définir quelque chose qui explique la Prise de rester ouvert jusqu'à ce que j'ai fini? Le code du serveur ne voit jamais une exception parce que le Client TCP n'est jamais arrêté, donc je sais il n'y a pas d'erreur.
Notre Administrateur Réseau n'a pas reçu son Degré d'Associés, de sorte que si elle s'avère être un problème avec le Serveur, merci de détaillé dans votre description de la façon de résoudre ce problème, parce que nous ne pourrions pas comprendre ce que vous dites.
Je m'excuse pour cet être si long, mais je veux m'assurer que vous les gens savent ce que je fais - et peut-être même lueur de certaines informations de ma technique!
Merci pour votre aide!
~Joe
Vous devez vous connecter pour publier un commentaire.
Vous devrait précéder l'envoyé de contenu avec la longueur de ce contenu. Votre boucle suppose que toutes les données sont envoyées avant la boucle s'exécute, alors qu'en réalité, votre boucle s'exécute tant que les données sont envoyées. Il y aura des moments où il n'y a pas de données en attente sur le fil, de sorte que la boucle s'arrête; pendant ce temps, le contenu est toujours envoyé à travers le fil. C'est pourquoi votre boucle est seulement en cours d'exécution une fois.
Si j'ai lu ton code correctement, vous avez obtenu (désolé pour le style c - je ne suis pas bon avec le c#:
Si je suis correct, alors cela signifie que vous devez... un peu plus là-dedans. Si vous voulez qu'il soit activé, la lecture de chaque téléchargement de la séquence, vous aurez envie d'une deuxième boucle:
Si vous souhaitez lire plusieurs téléchargements simultanément, vous aurez besoin de quelque chose de plus comme:
Votre exemple telnet est un peu contradictoire le comportement du code que vous décrivez - si jamais vous êtes en mesure d'obtenir quoi que ce soit sur le serveur, le "telnet <nom d'hôte> <portnumber>" devrait vous rendre à un écran vide assez rapidement (sur une machine windows dans l'invite de CMD qui est). Donc, c'est la première chose étrange - les meilleurs débogué avec wireshark, si.
Au niveau du Code, je pense que c'est peut être le problème avec cette ligne intérieure sur le serveur:
... while ((0 < len) && (ns.DataAvailable == true));
Vous dites que vous voulez en boucle pendant que vous étiez capable de lire quelque chose et même s'il existe des données disponibles.
Cependant, il se peut que le deuxième segment n'est pas fait pour le serveur, donc il n'y a pas de données disponibles, de sorte que vous sont en baisse de sortir de cette boucle.
Vous devriez boucle de réception de données tandis que vous lisez quelque chose et alors il n'y a pas eu d'erreur de lecture - ce qui garantit que, même sur les liaisons lentes vous sera fiable de recevoir les données.
Une note de côté:
J'ai l'avis de votre protocole de requête-réponse-requête-réponse type. Il fonctionne bien sur le réseau local, mais si vous avez besoin à l'avenir pour le faire fonctionner au cours de la haute-aller-retour-liens en temps, cela va devenir un gros goulot d'étranglement des performances (MS protocole SMB utilisé pour filetransfers ou TFTP fonctionne de cette manière).
(Disclaimer: je n'ai pas de code en C#, tellement pourrait avoir été mal à l'interprétation de la "DataAvailable()" de la méthode, de prendre cette FWIW).
Edit: sans doute ma réponse ci-dessus doit être corrigé en fonction de votre protocole - c'est à dire que vous auriez besoin de lire d'abord la longueur du fichier, et ensuite lire le fichier, car si vous prenez le texte, il va briser la façon dont vous avez conçu complètement.
Cela dit, avec le protocole TCP il ne faut jamais supposer que le nombre de write() les opérations sur le côté de l'expéditeur est le même que le nombre de read() opérations sur le côté du récepteur - dans certains cas, il peut être le cas (pas de perte de paquet, pas de Nagle) - mais dans le cas général, il ne serait pas vrai.