为什么不支持读取和写入我的PCL TcpSocketClient?

时间:2015-11-19 21:52:03

标签: c# sockets xamarin

我在我的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));
        }

    }

我认为这可能是因为我之后处理了流,所以我拿出了使用,但它仍然破坏了。

1 个答案:

答案 0 :(得分:1)

此代码存在多个问题。

  1. 是的,你不应该处理这些流。它们的寿命与连接的生命周期有关。
  2. NotSupportedException提供的内容可能是这一行:if (s.Length > 0)。网络流很可能不支持Length属性。
  3. 即使Length有效,它也会毫无用处,因为它会引入竞争条件:在访问Length和呼叫Read之间的时间内,可能会有更多数据到达。
  4. 使用Task.Delay等待服务器的响应是一个非常糟糕的主意。您不应该假设网络的速度有多快,尤其是在移动设备上!
  5. 所以,你的阅读代码是错误的。这样的事情应该有效:

    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的开发人员经常会在这里感到困惑。