我的Windows Phone 8应用程序中包含以下代码。
//connection code, done during app start
socket = new StreamSocket();
await socket.ConnectAsync(serverHostName, serviceName);
dataReader = new DataReader(socket.InputStream);
dataReader.InputStreamOptions = InputStreamOptions.Partial;
dataWriter = new DataWriter(socket.OutputStream);
建立连接后,我有另一个线程检查传入的网络数据包
await dataReader.LoadAsync(2048);
dataReader.ReadBytes(buffer);
----------
工作流程如下
工作状态'和'非工作状态'之间没有任何情况差异。
所以我试着调试一下。我为dataReader.LoadAsync设置了一个断点,并看到执行时无限期地等待执行。
为了确保服务器正确发送数据,我在Windows手机模拟器中运行了应用程序并在PC中运行了 WireShark网络分析器。我可以看到正在接收手机IP地址的数据包。
当有数据准备好在套接字中读取时,任何人都有任何关于dataReader.LoadAsync函数调用根本没有返回的提示吗?
答案 0 :(得分:2)
我遇到了同样的问题。对于蓝牙RFCOMM SPP串行端口设备尤其不利,因为底层的Rfcomm对象不提供设置ReadTimeout值的功能。 编辑:InputStreamOptions.Partial选项似乎正在使用UWP Win10平台,但只有在您已经了解了预期的数据时才有用。否则它会在最后一次通话时无限期等待。
当我在下面的参考文献中找到使用 CancellationTokenSource
来解决问题时,我几乎放弃了//connect your Windows.Devices.Bluetooth.Rfcomm.RfcommDeviceService
// see the Bluetooth chat example
[...]
StreamSocket streamSocket = new StreamSocket();
await streamSocket.ConnectAsync(...); //connect to Bluetooth device
DataReader dataReader = new DataReader(inputStream); // to read from the stream
try
{
var timeoutSource = new CancellationTokenSource(1000); // 1000 ms
uint numberBytesToRead = 256;
var data = await dataReader.LoadAsync(numberBytesToRead).AsTask(timeoutSource.Token);
}
catch (TaskCanceledException)
{
// we will get here, and everything looks fine, but the problem is:
// The underlying streamSocket is also closed!
// we can not re-use the streamSocket. Any more calls to LoadAsync results in exceptions (something about the object being not assigned...)
// we need to do a full await streamSocket.ConnectAsync(...) again, but that takes ~3 seconds.
}
所以这种方法只是一种蛮力的,最后的尝试,暂时停止。
来自@mayu的方法非常好(serialDevice.ReadTimeout),但仅适用于类Windows.Devices.SerialCommunication.Serial Device的设备,但不 on Windows.Devices.Bluetooth.Rfcomm.RfcommDeviceService。我不知道TCP / IP套接字的情况如何。
简而言之,RFCOMM SPP蓝牙连接是否有任何可用的超时? 或者.LoadAsync(1)将阻止的任何提前知道的方法,因为没有可用的新数据?
MSDN上的那个人有完全相同的问题,但MS也不知道答案:https://social.msdn.microsoft.com/Forums/vstudio/en-US/71ea17d4-ca16-43c2-ab43-02d5301def3f/chow-to-set-timeout-on-streamsocketreadasync?forum=wpdevelop
参考文献:
In UWP StreamSocket, can I read data with timeout and leave the connection open if timeout elapses
答案 1 :(得分:1)
"根据使用InputStreamOptions.Partial时的文档,您应该使用UnconsummedBufferLength而不是硬编码值"
该样本似乎已被打破。
"等待reader.LoadAsync(reader.UnconsumedBufferLength);"相当于
等待reader.LoadAsync(0);然后它就无法读取任何数据,因为你没有可以读取的缓冲区。
我现在正在测试它,看起来好像" reader.InputStreamOptions = Partial;"完全没有效果。我唯一的解决方法是降低读取超时。
答案 2 :(得分:0)
根据使用InputStreamOptions.Partial时的文档,您应该使用UnconsummedBufferLength而不是硬编码值:
DataReader reader = new DataReader(clientSocket.InputStream);
// Set inputstream options so that we don't have to know the data size
reader.InputStreamOptions = Partial;
await reader.LoadAsync(reader.UnconsumedBufferLength);
答案 3 :(得分:0)
我在使用Windows Remote Arduino库和SerialUSB流时遇到了类似的问题。我不得不更改此库并调用LoadAsync(1)而不是原始的LoadAsync(100)。现在代码工作正常。
答案 4 :(得分:0)
对于串行设备,您需要设置
device.ReadTimeout = TimeSpan.FromMilliseconds(100);
在缓冲区已满之前返回LoadAsync。
答案 5 :(得分:0)
The only way I found to get round not knowing the size of the data before reading was to read one byte at a time until I got a timeout. Feels horrid, but works. Is there a better way yet?
private async Task ReadData(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
DataReaderObject.InputStreamOptions = InputStreamOptions.Partial;
uint data = 0;
uint bufferLength = DataReaderObject.UnconsumedBufferLength;
var timeoutSource = new CancellationTokenSource(100); // 100 ms
try
{
while (true)
{
data = await DataReaderObject.LoadAsync(1).AsTask(timeoutSource.Token);
if (data > 0)
{
String temp = DataReaderObject.ReadString(data);
TemperatureValue.Text += temp.Trim();
}
}
}
catch (Exception)
{
;
}
}