StreamSocketListener在Raspberry Pi 3(IoT Core UWP)上从客户端随机接收空

时间:2018-03-27 14:22:59

标签: c# uwp raspberry-pi3 windowsiot windows-iot-core-10

我正在测试一个非常简单的Web服务器代码(从MSDN示例或我遗忘的地方复制它),我在带有IoT Core v.10.0.16299.309的Raspberry Pi 3 Model B上运行它。我做了一切正确的事情,包括在每个请求上配置套接字,代码大多数时间都在工作。

我只有一个客户端,每隔30秒就向这个Web服务发送3个非常简单的HTTP GET请求,只需要一个简单的URL:http://serverIP/get?id=123它会在一小时内正确返回结果,但请求对象是RANDOMLY由于一些奇怪的原因是空的。我无法弄明白为什么。

private StreamSocketListener _listener;
private int _bufferSize = 8192;

public async void Run(IBackgroundTaskInstance taskInstance)
{
    taskInstance.GetDeferral();
    _listener = new StreamSocketListener();
    _listener.ConnectionReceived += HandleRequest;
    await _listener.BindServiceNameAsync("9080");       
}

public async void HandleRequest(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
  try 
  {
    StringBuilder request = new StringBuilder()
    using (IInputStream input = args.Socket.InputStream)
    {
         byte[] data = new byte[_bufferSize];
         IBuffer buffer = data.AsBuffer();
         uint bytesRead = _bufferSize;
         while (bytesRead == _bufferSize)
         {
            await input.ReadAsync(buffer, _bufferSize, InputStreamOptions.Partial);                        
            request.Append(Encoding.UTF8.GetString(data, 0, data.Length));
                    bytesRead = buffer.Length;

             // Some other code here to process the request object
             // and respond it back to the client. They are irrelevant.

          } // while
      } // using
   } // catch
   catch (Exception ex)
   {
      // Log here
   }
   finally 
   { 
       args.Socket.Dispose();
   }
} // method

我认为线程有问题,所以我禁用了大部分异步和等待。有趣的是,结果很好。请求对象99%的罚款。在12个小时内,请求只有3-4次空。我不认为这是正确的解决方案......但我真的陷入了这个问题,无法弄清楚原因。任何帮助表示赞赏。

private StreamSocketListener _listener;
private int _bufferSize = 8192;

public async void Run(IBackgroundTaskInstance taskInstance)
{
    taskInstance.GetDeferral();
    _listener = new StreamSocketListener();
    _listener.ConnectionReceived += HandleRequest;
    _listener.BindServiceNameAsync("9080");     // ** No "await"
}

 // ** No "async"
public void HandleRequest(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
  try 
  {
    StringBuilder request = new StringBuilder()
    using (IInputStream input = args.Socket.InputStream)
    {
         byte[] data = new byte[_bufferSize];
         IBuffer buffer = data.AsBuffer();
         uint bytesRead = _bufferSize;
         while (bytesRead == _bufferSize)
         {
            // ** No "await"
            input.ReadAsync(buffer, _bufferSize, InputStreamOptions.Partial);                        
            request.Append(Encoding.UTF8.GetString(data, 0, data.Length));
                    bytesRead = buffer.Length;

             // Some other code here to process the request object
             // and respond it back to the client. They are irrelevant.

          } // while
      } // using
   } // catch
   catch (Exception ex)
   {
      // Log here
   }
   finally 
   { 
       args.Socket.Dispose();
   }
} // method

2 个答案:

答案 0 :(得分:1)

IInputStream.ReadAsync()文档包含一些可能有用的有趣信息:

  

始终从中返回的缓冲区中读取数据   IAsyncOperationWithProgress(IBuffer,UInt32)。不要以为   输入缓冲区包含数据。根据实施情况而定   读取的数据可能会被放入输入缓冲区,或者可能是   在不同的缓冲区中返回。对于输入缓冲区,你没有   实现IBuffer接口。相反,你可以创建一个   Buffer类的实例。

提供的缓冲区可能不包含数据。

您可以使用返回缓冲区并从中提取数据,也可以使用DataReader.ReadBuffer()(或您的DataReader.ReadString())从流中获取数据。

通常,使用DataReader来读取流中的数据比使用低级API更容易。

您的代码变为

 byte[] data = new byte[_bufferSize];
 IBuffer buffer = data.AsBuffer();
 uint bytesRead = _bufferSize;
 while (bytesRead == _bufferSize)
 {
    var readFromStreamBuffer = await input.ReadAsync(buffer, _bufferSize, InputStreamOptions.Partial);
    var readBytes = readFromStreamBuffer.ToArray();            
    request.Append(Encoding.UTF8.GetString(readBytes, 0, readBytes.Length));
    bytesRead = readFromStreamBuffer.Length;
  }

DataReader.ReadBuffer()

 byte[] data = new byte[_bufferSize];
 IBuffer buffer = data.AsBuffer();
 uint bytesRead = _bufferSize;
 var dataReader = new DataReader(input);
 while (bytesRead == _bufferSize)
 {
    await dataReader.LoadAsync(_bufferSize);

    var readFromStreamBuffer = dataReader.ReadBuffer();
    var readBytes = readFromStreamBuffer.ToArray();            
    request.Append(Encoding.UTF8.GetString(readBytes, 0, readBytes.Length));

    bytesRead = readFromStreamBuffer.Length;
  }

DataReader.ReadString()

 byte[] data = new byte[_bufferSize];
 IBuffer buffer = data.AsBuffer();
 uint bytesRead = _bufferSize;
 var dataReader = new DataReader(input);
 dataReader.UnicodeEncoding  = UnicodeEncoding.Utf8;
 while (bytesRead == _bufferSize)
 {
    await dataReader.LoadAsync(_bufferSize);
    request.Append(dataReader.ReadString(dataReader.UnconsumedBufferLength));

    bytesRead = readFromStreamBuffer.Length;
  }

答案 1 :(得分:0)

出于想法,我更改了我的代码以使用Socket.InputStream.AsStreamForRead(),然后使用.ReadLineAsync()只读取第一行进行测试。它看起来很稳定,经过12个多小时没有空的请求!!!

对于我需要的,这实际上很好,因为我并没有真正构建一个完整的功能Web服务器,所以我不需要得到完整的请求。我只需要获取HTTP GET QueryString并将参数传递给我的Raspberry Pi的GPIO。

正如Vincent所说,.ReadAsync()有一些非常有趣的行为。我一定会在以后尝试他的建议。

public async void HandleRequest(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
    string requestString;
    try
    { 
        Stream inStream = args.Socket.InputStream.AsStreamForRead();
        StreamReader reader = new StreamReader(inStream);
        requestString = await reader.ReadLineAsync();

         // Some other code here to process the request object
         // and respond it back to the client. They are irrelevant
    } // catch     
    catch (Exception ex)
    {
      // Log here
    }
    finally 
    { 
       args.Socket.Dispose();
    }
}