C# StreamSocketListener在Raspberry Pi 3(IoT Core UWP)上随机接收来自客户端的空数据
我正在测试一个非常简单的web服务器代码,或者是从MSDN示例中复制的,或者是我忘记的某个地方,我正在使用IoT Core v.10.0.16299.309在Raspberry Pi 3 Model B上运行它。我做了所有正确的事情,包括在每次请求时处理套接字,代码大部分时间都正常工作 我只有一个客户端,每30秒向这个web服务发送3个非常简单的HTTP GET请求,就像这样一个简单的URL:它在一个小时内正确但随机地返回结果,由于某种奇怪的原因,请求对象是空的。我不明白为什么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
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();
}
}