2009-08-10 27 views
6

Ho un'applicazione che ho scritto per la mia applicazione distribuita in tutta l'azienda per l'invio di dati tramite il nostro server Windows 2003 (con IIS 6.0 in esecuzione). Messaggi di testo di dimensioni ridotte, ma i messaggi più grandi contenenti più dati (circa 20 KB) non riescono a passare.Connessione client TCP

Imposta il buffer di byte sulla dimensione del buffer del client TCP. Ho notato che i miei dati venivano ricevuti sul server; tuttavia, ha eseguito il looping della routine di ricezione solo una volta e i miei file di grandi dimensioni avevano sempre esattamente la dimensione della dimensione del buffer o 8 KB sul nostro server. In altre parole, il mio codice esegue solo un ciclo prima che il server chiuda la connessione socket.

Pensando che potrebbe esserci un problema con il riempimento dell'intero buffer, ho provato a limitare le mie letture/scritture a solo 1 KB, ma questo ha provocato il nostro server chiudere il socket dopo aver ricevuto 1 KB prima di chiudere la connessione.

Invio il messaggio di errore del server al client in modo che possa visualizzarlo. Il messaggio di errore specifico che ricevo dal client è:

“Unable to write data to the transport connection: An established connection was aborted by the software in your host machine.”

ho aggiornato il mio applicazione server in modo che il socket TCP sottostante avrebbe usato “keep alive” con questa linea:

client.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true); 

Ora, ogni volta tento di inviare un messaggio, il cliente riceve l'errore:

“Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host.”

amministratore nostra rete mi ha detto che non ha un firewall o qualsiasi porte bloccate sul nostro server interno.

Cerca su Google gli errori, ho trovato post che suggeriscono che le persone provano a telnet nel server. Ho usato le loro direzioni al telnet al server, ma non sono sicuro di cosa fare della risposta:

C:> telnet Welcome to Microsoft Telnet Client

Escape Character is ‘CTRL+]’

Microsoft Telnet> open cpapp 500 Connecting To cpapp…

Questo è tutto quello che ricevo. Non ricevo mai un errore, e lo schermo Telnet di Microsoft cambierà in "Premere un tasto qualsiasi per continuare ..." - Immagino che vada in timeout, ma il mio codice è in qualche modo in grado di connettersi.

Ho provato altre porte in codice e tramite Telnet compresi 25, 80 e 8080. Telnet ha rilasciato la porta 25, ma la mia applicazione sembra leggere il primo ciclo, non importa quale porta gli dica di eseguire.

Ecco il mio codice che viene eseguito sul client:

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; 
    } 
} 

Ecco il mio codice che viene eseguito sul server:

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(); 
    } 
} 

Perché lo domanda Continua la lettura da parte del Cliente TCP ? Ho dimenticato di impostare qualcosa che dice allo Socket di rimanere aperto finché non ho finito? Il codice server non vede mai un'eccezione perché il Client TCP non viene mai fermato, quindi so che non ci sono errori.

Il nostro amministratore di rete non ha ancora ricevuto la sua laurea, quindi se si scopre che si tratta di un problema con il server, vi preghiamo di fornire una descrizione dettagliata su come risolverlo, perché potremmo non capire quello che state dicendo .

Mi scuso per il fatto che sia così lungo, ma voglio essere sicuro che la gente là fuori sappia cosa sto facendo - e forse anche qualche informazione dalla mia tecnica!

Grazie per l'aiuto! ~ Joe

risposta

6

È necessario precedere il contenuto inviato con la lunghezza di tale contenuto. Il ciclo presume che tutti i dati vengano inviati prima dell'esecuzione del ciclo, quando in realtà il ciclo viene eseguito mentre i dati vengono inviati.Ci saranno momenti in cui non ci sono dati in attesa sul filo, quindi il ciclo termina; nel frattempo, il contenuto è ancora inviato attraverso il filo. Ecco perché il tuo ciclo è in esecuzione una sola volta.

+0

No scherzo? Immagino che abbia senso ora. Continuavo a pensare che qualcosa doveva essere configurato sul server. Questo aiuta un * sacco *! Grazie! – jp2code

+0

come lo farei? "precedere il contenuto inviato con la lunghezza di quel contenuto" non ho la lunghezza del contenuto inviato? –

+0

Se non si conosce la lunghezza, ovviamente non si invia la lunghezza sul filo. – Amy

1

Se leggo il codice correttamente, hai praticamente avuto (scusate per la c-style - Non sono bravo con C#:

 
do 
{ 
    socket = accept(); 
    read(socket, buffer); 
}while(not_done); 

se sono corrette, allora . significa che è necessario ... un po 'più in là Se si vuole che essere serializzato, la lettura di ogni upload in sequenza, si vorrà un secondo ciclo:

 
do 
{ 
    socket = accept(); 
    do { read(socket, buffer); not_done_reading=...; } while (not_done_reading); 
}while(not_done); 

Se volete leggere l'upload multiplo simultaniously, avrai bisogno di qualcosa di più simile a:

 
do 
{ 
    socket = accept(); 
    if(!fork()) 
    { 
    do { read(socket, buffer); not_done_reading=...; } while (not_done_reading); 
    } 
}while(not_done); 
1

Il vostro esempio Telnet è un po 'in contraddizione con il comportamento del codice che si descrive - se siete mai in grado di ottenere nulla sul server, il "telnet <hostname> <portnumber>" dovrebbe arrivare a un vuoto schermo abbastanza rapidamente (su Windows Machine nel prompt CMD che è). Quindi, questa è la prima cosa strana: il miglior debugging con wireshark, though.

Codice-saggio, penso che potrebbe essere un problema con la linea interna sul server:

... while ((0 < len) & & (ns.DataAvailable == true));

Si dice che si desidera eseguire il ciclo mentre si è in grado di leggere qualcosa e mentre sono disponibili alcuni dati.

Tuttavia, è possibile che il secondo segmento non sia ancora arrivato al server, quindi non ci sono ancora dati disponibili, quindi stai cadendo da questo ciclo.

Si dovrebbe eseguire un ciclo di ricezione dei dati mentre si sta leggendo qualcosa e mentre non si è verificato alcun errore di lettura, questo garantisce che anche sui collegamenti lenti verranno ricevuti i dati in modo affidabile.

Una nota a margine:

ho notato il protocollo è di tipo richiesta-risposta-richiesta-risposta. Funziona bene sulla LAN, ma se in futuro dovessi farlo funzionare con i collegamenti high-round-trip-time, questo diventerà un grosso collo di bottiglia per le prestazioni (il protocollo MS SMB utilizzato per i trasferimenti di file o TFTP funziona in questo modo) .

(Disclaimer: non ho scritto molto codice in C#, quindi avrei potuto sbagliare nell'interpretazione del metodo "DataAvailable()", prendi questo FWIW).

Modifica: probabilmente la mia risposta di cui sopra avrebbe dovuto essere corretta in base al protocollo, cioè dovresti prima leggere la lunghezza del file e poi leggere il file, poiché se lo prendi alla lettera, si romperà modo in cui l'hai progettato completamente.

Detto questo, con TCP non si dovrebbe mai assumere che il numero di operazioni di scrittura() sul lato mittente sia uguale al numero di operazioni read() sul lato ricevitore - in alcuni casi potrebbe essere il caso (nessun pacchetto perdita, niente Nagle) - ma nel caso generale non sarebbe vero.

Problemi correlati