我在我的PCL Xamarin应用程序中使用https://github.com/rdavisau/sockets-for-pcl并尝试发送/接收到我的网络上的服务器。目前我正在使用Android(实际手机)进行测试。我能够成功连接(我知道这是因为我的服务器显示连接而且应用程序没有引发异常),但是当我尝试读取或写入时,我收到
“不支持操作。”
服务器给出:
“无法从传输连接读取数据:远程主机强行关闭现有连接。”
我查看了有关此异常的其他帖子,看起来IPv4和IPv6之间不匹配。但我不使用localhost,我使用网络IP所以应该没问题?具体来说,我在同一地址(192.168.2.169和端口207)主持和连接。这是我的代码:
//Functions called by 2 buttons "Connect" and "Send"
//This works. I connect.
public async void SocketConnect(object sender, EventArgs args)
{
try
{
client = new TcpSocketClient();
await client.ConnectAsync(ipEntry.Text, int.Parse(portEntry.Text));
// we're connected!
connectBtn.Text = "Connected";
}
catch (Exception e)
{
var notificator = DependencyService.Get<IToastNotificator>();
bool tapped = await notificator.Notify(ToastNotificationType.Error,
"Error", e.Message, TimeSpan.FromSeconds(10));
}
}
public async void SocketSend(object sender, EventArgs args)
{
try
{
if(client==null)
{
var notificator = DependencyService.Get<IToastNotificator>();
bool tapped = await notificator.Notify(ToastNotificationType.Error,
"Error", "Connect First Please", TimeSpan.FromSeconds(10));
}
byte[] toSend = System.Text.Encoding.UTF8.GetBytes(toSendEntry.Text);
using (Stream s = client.WriteStream)
{
s.Write(toSend, 0, toSend.Length);
await s.FlushAsync();
} //Fails Here with Operation is not supported.
await Task.Delay(70);
using (Stream s = client.ReadStream)
{
if (s.Length > 0)
{
byte[] response = new byte[s.Length];
s.Read(response, 0, (int)s.Length);
responseFromServer.Text = response.ToString();
}
}
}
catch (Exception e)
{
var notificator = DependencyService.Get<IToastNotificator>();
bool tapped = await notificator.Notify(ToastNotificationType.Error,
"Error", e.Message, TimeSpan.FromSeconds(10));
}
}
我认为这可能是因为我之后处理了流,所以我拿出了使用,但它仍然破坏了。
答案 0 :(得分:1)
此代码存在多个问题。
NotSupportedException
提供的内容可能是这一行:if (s.Length > 0)
。网络流很可能不支持Length
属性。Length
有效,它也会毫无用处,因为它会引入竞争条件:在访问Length
和呼叫Read
之间的时间内,可能会有更多数据到达。Task.Delay
等待服务器的响应是一个非常糟糕的主意。您不应该假设网络的速度有多快,尤其是在移动设备上!所以,你的阅读代码是错误的。这样的事情应该有效:
var ms = new MemoryStream();
var buffer = new byte[1024]; // real size doesn't matter. too small will make
// your code slow. too big will just waste memory
for(;;)
{
var len = await s.ReadAsync(buffer, 0, buffer.Length);
if (len == -1)
break; // server closed the connection!
ms.Write(buffer, 0, len); // note that we use len here, as
// Read might have not used the whole buffer
}
var response = ms.ToArray();
此代码读取套接字中的所有可用数据,直到连接关闭。如果服务器不应该关闭连接,则需要在数据前加上长度或在末尾使用某种标记。例如。 HTTP使用\r\n\r\n
标记标题的结尾。
另请注意,Read
/ ReadAsync
永远不会返回0.它只会在返回之前等待任何数据到达。这是一个重点,不熟悉Unix风格的I / O的开发人员经常会在这里感到困惑。