Mam aplikację, którą napisałem dla mojej aplikacji rozpowszechnianą w całej firmie, aby wysłać dane do mnie za pośrednictwem naszego serwera Windows 2003 (z uruchomionymi usługami IIS 6.0). Małe wiadomości tekstowe przechodzą, ale większe wiadomości zawierające więcej danych (około 20 KB) nie są przesyłane.Połączenie klienta TCP
Ustawiam bufor bajtowy na rozmiar bufora klienta TCP. Zauważyłem, że moje dane były odbierane na serwerze; jednakże tylko pętle przechodzą przez procedurę odbierania jeden raz, a moje duże pliki zawsze były dokładnie rozmiaru bufora lub 8 KB na naszym serwerze. Innymi słowy, mój kod wykonuje tylko jedną pętlę, zanim serwer zamknie połączenie z gniazdem.
Myśląc, że może być problem z wypełnieniem całego bufora, próbowałem ograniczyć zapis/zapis do zaledwie 1 KB, ale to tylko spowodowało, że nasz serwer zamykał gniazdo po otrzymaniu 1 KB przed zamknięciem połączenia.
Wysyłam komunikat o błędzie serwera z powrotem do klienta, dzięki czemu mogę go wyświetlić. Konkretny komunikat o błędzie, że otrzymuję od klienta jest:
“Unable to write data to the transport connection: An established connection was aborted by the software in your host machine.”
zaktualizowałem moją aplikację serwera tak, że ogólny Socket TCP użyłby „keep alives” z tej linii:
client.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true);
Teraz, ilekroć I próba wysyłania wiadomości, klient otrzymuje błąd:
“Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host.”
Administrator Nasza sieć powiedział mi, że nie posiada żadnych portów zapory lub zablokowane na naszym serwerze wewnętrznym.
Podczas wyszukiwania błędów znalazłem wpisy sugerujące, że ludzie próbują telnetować się na serwerze. Użyłem ich wskazówek do telnetu na serwerze, ale nie jestem pewien, co zrobić z odpowiedzią:
C:> telnet Welcome to Microsoft Telnet Client
Escape Character is ‘CTRL+]’
Microsoft Telnet> open cpapp 500 Connecting To cpapp…
To wszystko, co otrzymuję. Nigdy nie dostaję błędu, a ekran Telnet Microsoftu ostatecznie zmieni się na "Naciśnij dowolny klawisz, aby kontynuować ..." - Myślę, że to się skończyło, ale mój kod jest jakoś w stanie się połączyć.
Próbowałem innych portów w kodzie i przez Telnet, w tym 25, 80 i 8080. Telnet uruchamia port 25, ale moja aplikacja wydaje się czytać pierwszą pętlę bez względu na port, który mam mu uruchomić.
Oto mój kod, który działa na klientach:
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;
}
}
Oto mój kod, który działa na serwerze:
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();
}
}
Dlaczego nie moja aplikacja Czytaj dalej od Klienta TCP ? Czy zaniedbałem ustawienie czegoś, co mówi, że Gniazdo pozostaje otwarte, dopóki nie skończę? Kod serwera nigdy nie widzi wyjątku, ponieważ klient TCP nigdy się nie zatrzymuje, więc wiem, że nie ma błędu.
Nasz administrator sieci nie otrzymał jeszcze tytułu Associates Degree, więc jeśli okaże się, że jest to problem z Serwerem, prosimy o szczegółowe wyjaśnienie, jak rozwiązać ten problem, ponieważ możemy nie rozumieć, co mówisz .
Przepraszam za to, że jest tak długo, ale chcę się upewnić, że ludzie na zewnątrz wiedzą, co robię - a może nawet pobudzić trochę informacji z mojej techniki!
Dzięki za pomoc! ~ Joe
Bez żartów? Myślę, że ma to teraz sens. Cały czas myślałem, że coś trzeba skonfigurować na serwerze. To pomaga * dużo *! Dziękuję Ci! – jp2code
jak to zrobić? "poprzedza wysłaną zawartość długością tej treści" nie mam długości wysłanej treści? –
Jeśli nie znasz długości, to oczywiście nie wysyłasz długości na przewodzie. – Amy