0

Ich habe eine CSharp-Anwendung (CF2.0) für Windows Mobile 6.5-Terminals. Ich habe einen Thread, der alle 1,5 Minuten versucht, sich mit einem PHP WebService zu verbinden. Ich versuche, die Antwort dieses PHP WebService mit einer ReadToEnd() Methode zu lesen. Es funktioniert, aber manchmal (zufällig) blockiert die Routine auf ReadToEnd(). Ich weiß nicht warum.Verwenden Sie StreamReader mit HttpWebResponse Block ReadToEnd()

Dies ist der Code:

public static string CallWebServiceProblem(string url, int timeout) 
{ 

    string s = ""; 

    ServicePointManager.DefaultConnectionLimit = 10; 


    _logger.Trace("web service: {0} timeout: {1}", url, timeout); 
    HttpWebRequest wrGETURL = null; 
    try 
    { 
     bool isProblema = url.IndexOf("lsp_r2") >= 0; 
     if (isProblema) 
      _logger.Info("Sono in lsp_r2..."); 

     wrGETURL = (HttpWebRequest)WebRequest.Create(url); 
     wrGETURL.Credentials = CredentialCache.DefaultCredentials; 

     wrGETURL.ReadWriteTimeout = 10000; // Per vedere se sistema un po' i timeout... 
     if (timeout != 0) 
      wrGETURL.Timeout = 3000; // timeout... 

     Stream ojstream = null; 
     StreamReader sr = null; 
     HttpWebResponse httpresponse = null; 

     try 
     { 
      if (isProblema) 
       _logger.Info("lsp_r2: Chiamo GetResponse..."); 

      httpresponse = (HttpWebResponse)wrGETURL.GetResponse(); 

      if (isProblema) 
       _logger.Info("lsp_r2: Chiamo GetResponseStream..."); 

      ojstream = httpresponse.GetResponseStream(); 
      Encoding encode = System.Text.Encoding.GetEncoding("utf-8"); 

      if (isProblema) 
       _logger.Info("lsp_r2: Chiamo StreamReader..."); 

      sr = new StreamReader(ojstream, encode); 

      if (isProblema) 
       _logger.Info("lsp_r2: inizio a leggere"); 

      s = sr.ReadToEnd(); 
      if (isProblema) 
      { 
       _logger.Info("lsp_r2: terminato di leggere " + s.Length + " caratteri"); 
       System.Diagnostics.Debug.WriteLine("lsp_r2: terminato di leggere " + s.Length + " caratteri"); 
#if DEBUG 
       // _logger.Info("lsp_r2: ho letto " + s); 
       System.Diagnostics.Debug.WriteLine("lsp_r2: ho letto " + s); 
#endif 
      } 
     } 
     catch (Exception ex) 
     { 
      _logger.Error("web service: {0} timeout: {1} exception: {2} - {3}", url, timeout, ex.Message, ex.InnerException != null ? ex.InnerException.Message : "??"); 
      throw new Exception(ex.Message); 
     } 
     finally 
     { 

      if (isProblema) 
       _logger.Info("lsp_r2: Concludo..."); 

      if (sr != null) 
      { 
       sr.Close(); 
       sr.Dispose(); 
      } 

      if (ojstream != null) 
      { 
       ojstream.Close(); 
       ojstream.Dispose(); 
      } 

      if (httpresponse != null) 
      { 
       httpresponse.Close(); 
      } 
     } 
    } 
    catch (Exception ex) 
    { 
     throw new Exception(ex.Message); 
    } 
    finally 
    { 

    } 

    return s; 

} 

ich diese Routine für einige PHP WS in meiner Anwendung verwenden, aber ich habe das Problem nur mit einem, der eine Menge von Zeichen zurückgibt (kann 8000 und mehr .. .). Die von WS zurückgegebene Zeichenfolge ist eine Zeichenfolge, die mit CRLF endet. Werte werden mit | getrennt und Datensätze werden mit § getrennt (können diese ASCII Zeichen ein Problem sein ??). So etwas (dieses Beispiel hat nur einen Datensatz)

80643 | 882168 | 145 | 1 | 3 | 1 | 0 | 0 | 0 | 0 | 0 | 2016-04-04 19: 43: 24 | 1900- 01-01 00: 00: 00 | 1900-01-01 00: 00: 00 | 1900-01-01 00: 00: 00 | 2016-04-04 19: 43: 42 ||||| 2016-04- 04 09: 45: 42 | 08: 45 1TG GALDINO, 8 Mailand Ditta: ZEBRE X PROVA() || Int.pr: Orario Continuato | 2016-04-04 10: 45: 42 | V LARGA, Ditta:() | LARGA | Int.co: Orario Continuato || 0 | 2016-04-04 08: 46: 03 | 2016-04-04 19: 43: 42 | 2 || 0 | 0000-00-00 00: 00: 00§

Wenn der Block occours, in meinem log ich sehe "lsp_r2: inizio ein leggere" (die Zeile vor dem ReadToEnd) und ich sehe nicht, lsp_r2: terminato di leggere (die Zeile nach der ReadToEnd) .

Ich habe auch versucht, so etwas wie diese

int totCar = 0; 
while (sr.EndOfStream == false) { 
    int numCar = sr.Peek(); 

    char[] caratteri = new char[numCar]; 

    sr.Read(caratteri, 0, numCar); 

    string newString = new string(caratteri); 
    // Arrivano un sacco di null.. li rimuovo 
    int posNull = newString.IndexOf('\0'); 
    if (posNull >= 0) 
     newString = newString.Substring(0, posNull); 

    s += newString; 
    totCar += newString.Length; 

    // if (isProblema) 
    //  _logger.Info("lsp_r2: letti: " + numCar + " caratteri"); 

} 

mit Aber ich habe auch sr.Read

Es ist etwas, ich weiß nicht, über die Socket-Kommunikation habe Problem mit, dass der Block Gelesen? Sollte ich eine ReadLine verwenden, weil die Linie mit CRLF endet? Muss ich andere Methoden verwenden?

Entschuldigung für mein Englisch. Lassen Sie es mich wissen, wenn ich weitere Informationen geben muss.

TIA

Alessandro

+0

Nicht nur die Anfrage/lesen kann blockieren, auch asynchrone WebRequest kann fehlschlagen. Die Ursache kann ein getrenntes Netzwerk und viele andere sein (Sie müssen Netzwerk-Traces und Server-Ereignisprotokolle analysieren). Ich würde Ihren Code in einen neuen Thread einfügen und dann thread.join nach dem Timeout verwenden, um zu testen, ob der Thread fertig ist. Wenn die Anfrage nicht erfolgreich war, können Sie den Thread erneut versuchen. – josef

+0

Danke @josef hast du ein Beispiel, wie man das umsetzt? Von welcher Auszeit sprichst du? –

Antwort

0

Hier ist ein nicht markiert Codefragment, wie dies zu tun mit einem Gewinde und externer timeout (zweiter Thread):

using System; 
using System.Web; 
using System.Threading; 

public class myWebRequest:IDisposable{ 
    public class myEventArgs:System.EventArgs{ 
     public string msg; 
     public myEventArgs(string s){ 
      msg=s; 
     } 
    } 
    public delegate void myDelegate (myEventArgs args); 

     public myDelegate theDelegate; 

     void onUpdate (myEventArgs arg) 
     { 
      if (theDelegate != null) 
       theDelegate (arg); 
     } 

     Thread myThread = null; 
     Thread watchThread = null; 

    object lockObject = new object(); 
    bool bThreadRunning = false; 

    public myWebRequest(){ 
    } 
    public void Dispose(){ 
     if (watchThread != null) { 
      watchThread.Abort(); 
      watchThread = null; 
     } 
     if (myThread != null) { 
      myThread.Abort(); 
      myThread = null; 
     } 
    } 

    public void startRequest(){ 
     if (myThread != null) { 
      myThread.Abort(); 
      myThread = null; 
     } 
     myThread = new Thread (theThread); 
     myThread.Start(); 

     //start the watch thread 
     if (watchThread != null) { 
      watchThread.Abort(); 
      watchThread = null; 
     } 
     watchThread = new Thread (theWatchThread); 
     watchThread.Start(); 
    } 

    void theWatchThread(){ 
     try{ 
      Thread.Sleep (5000); 
      if (bThreadRunning && myThread != null) { 
       //thread is running, try a join 
       if (myThread.Join (5000)) { 
        //join did work, although thread should have finished 
        myThread.Abort(); 
        myThread = null; 
        bThreadRunning = false; 
        onUpdate(new myEventArgs("failed")); 
       } 
      } 
     }catch(ThreadAbortException ex){ 
     } 
     catch(Exception ex){ 
     } 
    } 

    void theThread(){ 
     string sMsg = ""; 
     try { 
      bThreadRunning=true; 
      //call the possibly blocking function 
      sMsg=myWebRequest.CallWebServiceProblem("url", 4000); 
      onUpdate(new myEventArgs(sMsg)); 
     }catch(ThreadAbortException ex){ 

     } 
     catch (Exception ex) { 

     } 
     bThreadRunning = false; 
    } 

    static string CallWebServiceProblem(string url, int timeout) 
    { 

     string s = ""; 

     ServicePointManager.DefaultConnectionLimit = 10; 


     _logger.Trace("web service: {0} timeout: {1}", url, timeout); 
     HttpWebRequest wrGETURL = null; 
     try 
     { 
      bool isProblema = url.IndexOf("lsp_r2") >= 0; 
      if (isProblema) 
       _logger.Info("Sono in lsp_r2..."); 

      wrGETURL = (HttpWebRequest)WebRequest.Create(url); 
      wrGETURL.Credentials = CredentialCache.DefaultCredentials; 

      wrGETURL.ReadWriteTimeout = 10000; // Per vedere se sistema un po' i timeout... 
      if (timeout != 0) 
       wrGETURL.Timeout = 3000; // timeout... 

      Stream ojstream = null; 
      StreamReader sr = null; 
      HttpWebResponse httpresponse = null; 

      try 
      { 
       if (isProblema) 
        _logger.Info("lsp_r2: Chiamo GetResponse..."); 

       httpresponse = (HttpWebResponse)wrGETURL.GetResponse(); 

       if (isProblema) 
        _logger.Info("lsp_r2: Chiamo GetResponseStream..."); 

       ojstream = httpresponse.GetResponseStream(); 
       Encoding encode = System.Text.Encoding.GetEncoding("utf-8"); 

       if (isProblema) 
        _logger.Info("lsp_r2: Chiamo StreamReader..."); 

       sr = new StreamReader(ojstream, encode); 

       if (isProblema) 
        _logger.Info("lsp_r2: inizio a leggere"); 

       s = sr.ReadToEnd(); 
       if (isProblema) 
       { 
        _logger.Info("lsp_r2: terminato di leggere " + s.Length + " caratteri"); 
        System.Diagnostics.Debug.WriteLine("lsp_r2: terminato di leggere " + s.Length + " caratteri"); 
        #if DEBUG 
        // _logger.Info("lsp_r2: ho letto " + s); 
        System.Diagnostics.Debug.WriteLine("lsp_r2: ho letto " + s); 
        #endif 
       } 
      } 
      catch (Exception ex) 
      { 
       _logger.Error("web service: {0} timeout: {1} exception: {2} - {3}", url, timeout, ex.Message, ex.InnerException != null ? ex.InnerException.Message : "??"); 
       throw new Exception(ex.Message); 
      } 
      finally 
      { 

       if (isProblema) 
        _logger.Info("lsp_r2: Concludo..."); 

       if (sr != null) 
       { 
        sr.Close(); 
        sr.Dispose(); 
       } 

       if (ojstream != null) 
       { 
        ojstream.Close(); 
        ojstream.Dispose(); 
       } 

       if (httpresponse != null) 
       { 
        httpresponse.Close(); 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      throw new Exception(ex.Message); 
     } 
     finally 
     { 

     } 

     return s; 

    } 
} 

Um es aus einem Formular:

void doTest(){ 
     myWebRequest theRequest = new myWebRequest(); 
     theRequest.theDelegate += new myWebRequest.myDelegate (onReceive); 
    } 
    void onReceive(myWebRequest.myEventArgs args){ 
     //updateGUI? 
    } 

In onReceive erhalten Sie entweder "fehlgeschlagen" oder das Ergebnis.

Der obige Code ist nur ein Skelett ...

+0

Danke @josef Ich werde einen Test machen. Es gibt keine einfachere Methode, um ReadToEnd ein Timeout hinzuzufügen. –

+0

Das Problem ist, dass die API fehlerhaft ist und nicht immer Timeout. Die Problemumgehung ist also schwierig. Selbst mit einer asynchronen Codeänderung können Sie solche Probleme ausführen. – josef