【发布时间】:2018-11-14 10:51:24
【问题描述】:
如何正确实现使用 WriteStream.WriteAsync() 发送字符串和使用 ReadStream.ReadAsync() 等待响应之间的延迟?
我正在使用 rda.SocketsForPCL 插件来创建 TCP 客户端套接字,然后创建相应的读写流。
当我使用 TimeSpan.FromMilliseconds(200)) 实现延迟时,我收到 System.NullReferenceException: Object reference not set to an instance of an object in VS 2017。我是 C# 和 Xamarin 的新手,我不确定除上述方法外,如何实现不会引发异常的延迟。
是否有一个“全局”异常处理程序可以以某种方式实现以处理诸如此类的异常,因为 VS 2017 不会破坏代码并准确显示异常实际发生的位置?
我在 Xamarin.Forms 中实现了以下活动页面,但它不允许我使用 UpdateUserDataAsync() 函数中注释的 TimeSpan.FromMilliseconds(200)); 实现延迟下面:
public InputPage ()
{
try
{
InitializeComponent();
}
catch (Exception ex)
{
string err = ex.Message;
throw;
}
client = SharedSocket.Instance().getSocket(); // Get persistent Socket ===> client connection
UpdateUserDataAsync(); // Used to update the contents of the Listview
loadSampleData(); // Load the Items in the ListView
BindingContext = this;
this.BindingContext = new Relays(); // Binding the Listview items
var neg = lstView.BindingContext as Relays;
InputID = neg.ID;
}
private async void UpdateUserDataAsync() // Request and Receive Controller Name
{
byte[] rv = new byte[] { 0x01, 0x01, 0x01 0x01, 0x01, 0x01, 0x01 }; // Request
Send_CntrP(rv); // Send request
//await Task.Delay(TimeSpan.FromMilliseconds(200));
rec2 = await ReceiveByte();
}// UpdateUserDataAsync
private void loadSampleData()
{
ObservableCollection<Relays> lisInputs = new ObservableCollection<Relays>();
if (rec2.Length >= 4)
{
byte[] states = Encoding.ASCII.GetBytes(rec2); // Create byte array of received string
for (int j=6; j<22; j++)
{
switch (states[j])
{
case 0x00:
lisInputs.Add(new Relays { ID = j - 5, Name = "ERROR" + (j - 5), State = "ERROR" });
break;
case 0x01:
lisInputs.Add(new Relays { ID = j - 5, Name = "IOK" + (j - 5), ImageUrl = "round_on.png", State= "Toggle"});
break;
case 0x02:
lisInputs.Add(new Relays { ID = j - 5, Name = "IOK" + (j - 5), ImageUrl = "round_on.png", State = "ON"});
break;
case 0x03:
lisInputs.Add(new Relays { ID = j - 5, Name = "IOK" + (j - 5), ImageUrl = "round_on.png", State = "OFF"});
break;
case 0x04:
lisInputs.Add(new Relays { ID = j - 5, Name = "IOK" + (j - 5), ImageUrl = "round_on.png", State = "NO"});
break;
case 0x05:
lisInputs.Add(new Relays { ID = j - 5, Name = "IOK" + (j - 5), ImageUrl = "round_on.png", State = "NC"});
break;
case 0x10:
lisInputs.Add(new Relays { ID = j - 5, Name = "IOK" + (j - 5), ImageUrl = "round_on.png", State = "SC"});
break;
case 0x11:
lisInputs.Add(new Relays { ID = j - 5, Name = "IOK" + (j - 5), ImageUrl = "round_on.png", State = "OC"});
break;
}
}
}
else
{
for (int i = 0; i < num; i++)
{
Images[i] = "round_off.png";
InputName[i] = "ERROR";
InputOn[i] = false;
InputState[i] = "ERROR";
lisInputs.Add(new Relays { Name = InputName[i] + i, ImageUrl = Images[i], ID = i, State = InputState[i] });
}
}
lstView.ItemsSource = lisInputs;
}
public class MyListItemEventArgs : EventArgs
{
public Relays MyItem { get; set; }
public MyListItemEventArgs(Relays item)
{
this.MyItem = item;
}
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// +++++++++++++++++++++++ Sending Messages+++++++++ +++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public async void Send_CntrP(byte[] Comms)
{
var Len = Comms.Length; // Read the byte array Length
if (client.Socket.Connected && Len <= 23) // No longer than 22 bytes of data to be sent
{
try
{
await client.WriteStream.WriteAsync(Comms, 0, Len); // Send data of specified Length
await client.WriteStream.FlushAsync(); // Make sure all the buffer output data is sent
await Task.Delay(TimeSpan.FromMilliseconds(200)); // Delay before next TX to ensure buffer is emptied correctly
}
catch (Exception ex) // Exception Handler
{
return;
throw ex;
}
}// Client Connected
else
{
XFToast.ShortMessage("Error updating name.\n\rPlease check the connection or length of the entry"); //Android Native Toast Message
}
}// Send_CntrP
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++ Receiving Messages +++++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public async Task<string> ReceiveByte() // Receive messages Asynchronously
{
int bytesRec = 0;
var buffer = new byte[28];
if (client.Socket.Connected) // Check Socket connection
{
while (bytesRec != -1) // Read received data ---> byte-by-byte
{
try
{
bytesRec = await client.ReadStream.ReadAsync(buffer, 0, 28);
}
catch (Exception ex) // Exception Handler (to prevent App crash)
{
XFToast.ShortMessage("Error receiving message.\n\rPlease check the WIFI connection.");
return "ERROR"; // Return an "ERROR" message if failed
throw ex;
}
var meh = buffer.ToArray();
rec2 = System.Text.Encoding.UTF8.GetString(meh);
if (rec2.Length >= 1 && rec2.Length < 30)
{
return await Task.FromResult(rec2); // Return a string
}
else
{
//await DisplayAlert("Error", "Error receiving message.", "OK");
XFToast.ShortMessage("Error receiving message.\n\rPlease verify the connection."); //Android Native Toast Message
return "ERROR"; // Return an "ERROR" message
}
}// Reading response
}// Client
else
{
return err; // Return a "Connection Error" string when no connection is available
}
return rec2; // Return the received bytes in a string
}// ReceiveByte
//
++++++++++++++++++++++++++++++++++++++++++++++++
}
我很抱歉这篇长文,但我已经为这个问题苦苦挣扎了一段时间,我没有足够的经验来处理所有异步方法和异常“查找”,然后用 VS 2017 和 Xamarin 处理它们因为我还在学习基础知识:(
提前感谢您的任何帮助/建议。
【问题讨论】:
-
我通常将读写代码放在同一个锁中,这样一次只能发生一个。然后,您永远不会同时进行读取和写入,并且您总是在读取之前等待写入完成。
-
@jdweng,我如何将它们放在你提到的同一个锁(或块)中?
标签: c# sockets xamarin xamarin.forms exception-handling