C# StreamSocketListener在Raspberry Pi 3(IoT Core UWP)上随机接收来自客户端的空数据

C# StreamSocketListener在Raspberry Pi 3(IoT Core UWP)上随机接收来自客户端的空数据,c#,uwp,raspberry-pi3,windowsiot,windows-iot-core-10,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:它在一个小时内正确但随机地返回结果,由于某种奇怪的原因,请求对象是空的。我不明白为什么 private

我正在测试一个非常简单的web服务器代码,或者是从MSDN示例中复制的,或者是我忘记的某个地方,我正在使用IoT Core v.10.0.16299.309在Raspberry Pi 3 Model B上运行它。我做了所有正确的事情,包括在每次请求时处理套接字,代码大部分时间都正常工作

我只有一个客户端,每30秒向这个web服务发送3个非常简单的HTTP GET请求,就像这样一个简单的URL:它在一个小时内正确但随机地返回结果,由于某种奇怪的原因,请求对象是空的。我不明白为什么

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
文档中有一些有趣的信息可能会有所帮助:

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

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

您可以使用返回缓冲区并从中提取数据,或者在您的情况下使用或从流中获取数据

通常,使用API从流中读取数据比使用低级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;
  }
或与:

或与:


没了主意,我将代码改为使用Socket.InputStream.AsStreamForRead,然后使用.readlinesync只读取第一行进行测试。它看起来很稳定,12个多小时过去了,没有一个空的请求

对于我所需要的,这实际上很好,因为我并没有真正构建一个完整功能的web服务器,所以我不需要获得完整的请求。我所需要的就是获取HTTP get查询字符串,并将参数传递给我的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();
    }
}

taskInstance.getDeleral-这将获得一个临时对象,该对象最终将被GCed。当对象被GCed时,它可能会自动完成一些对象执行的延迟,一些对象不执行。你能试着在类字段中保留延迟,然后在完成后显式完成它吗?嗨,彼得。。谢谢你的回复。我想我也试过了,在_deleral.Completed执行之后,StreamSocketListen将不再侦听。如果我注释掉_deleral.Complete,但保留class变量,则行为与我描述的完全相同。如果我误解了您的意思,请纠正我。@userb00,您是否在响应的标题中添加了连接:close?是的,我确实以HTTP/1.1 200的形式发送了响应,确定,然后内容长度:xxx,然后连接:close谢谢Vincent,这是关于ReadSync的非常有趣的信息。。。这实际上有助于阐明这个问题!昨天晚上,我一时糊涂,把代码改成使用Socket.InputStream.AsStreamForRead,只需读一行代码就可以测试我需要的东西,实际上已经足够好了,而且看起来很稳定,没有随机的空传入请求。我会发布我的代码,非常简单。但是我一定会尝试你的建议。你的建议是有效的,因为AsStream创建的旧.Net流隐藏了IInputstream.ReadAsync的复杂性。您应该直接使用UWP DataReader,而不是创建最终以流/数据读取器实例结束的临时流:
 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;
  }
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();
    }
}