2015-09-13 107 views
0

我正在开发Windows Phone 8.1聊天应用程序,并在编程套接字互操作性期间发现了很多困难。Windows Phone 8.1 TCP套接字

主要问题是套接字上的“事件”,主要问题是:如何订阅OnData事件,例如,当数据来自服务器时如何检测事件?

我试图通过直接的方式解决它:从InputStream无限读取,并与50/50运气有效:有时该方法冻结UI流(甚至读取方法是async)。

我对这个问题进行了搜索,因为这对于那个重要的组件来说是一个非常奇怪的行为,即使在MSDN上也没有找到任何解决方案。在SO我发现像我的只有相同的解决方案,但他们也冻结UI流。

作为参考,我的应用程序基础结构是使用共享库中的Facade类的主要应用程序,Facade类获取泛型,指定具体行为(这是由于多个数据传输的原因而完成的)。对于TCP传输,我写道:

public class TCPTransport : ITransportProvider 
{ 
    private bool _connected { get; set; } 
    private StreamSocket _socket { get; set; } 

    private DataReader _input { get; set; } 

    public TCPTransport() 
    { 
     _socket = new StreamSocket(); 
    } 

    public async Task<bool> Connect(string host, int port) 
    { 
     try 
     { 
      await _socket.ConnectAsync(new HostName(host), port.ToString()); 

      if (OnConnect != null) 
       OnConnect(); 

      _connected = true; 
      _input = new DataReader(_socket.InputStream) 
      { 
       InputStreamOptions = InputStreamOptions.Partial 
      }; 

      _read(); 

      return _connected; 
     } 
     catch(Exception e) 
     { 
      Debug.WriteLine("[warn] cant conect to " + host + ":" + port + ". Additional: " + e.Message); 
      return false; 
     } 
    } 

    async private void _read() 
    { 
     while (true) 
     { 
      if (!_connected || _socket == null) break; 

      uint buffer = await _input.LoadAsync(2048); 
      string data = _input.ReadString(buffer); 

      if (OnData != null && data.Length != 0) 
       OnData(data); 
     } 
    } 

    public async Task<bool> Send(string data) 
    { 
     if (!_connected) return false; 

     try 
     { 
      await _socket.OutputStream.WriteAsync(Encoding.UTF8.GetBytes(data).AsBuffer()); 
     } 
     catch (Exception e) 
     { 
      System.Diagnostics.Debug.WriteLine("[warn] Exception send: " + e.Message); 
     } 

     return true; 
    } 

    public bool Close() 
    { 
     if (!_connected) return false; 

     _socket.Dispose(); 

     return true; 
    } 

    public Action OnConnect { get; set; } 
    public Action<string> OnData { get; set; } 
    public Action OnClose { get; set; } 
} 

我想我对使用该解决方案是错误的,但是如何从服务器端收听数据呢?

回答

0

无论好坏,StreamSocket API不是作为事件驱动的API设计的;它被设计为一个异步API。如果要在数据可用时提出事件,请使用事件而不是代理:

这是一个简单的示例(硬编码为www.microsoft.com,没有错误处理),显示如何模拟事件:

请注意,如果您在附加调试器的情况下运行,它将暂时冻结UI线程。当没有调试

// Create your own class to hold the data 
public class DataReceivedEventArgs : EventArgs 
{ 
    public uint DataCount { get; private set; } 
    public DataReceivedEventArgs(uint dataCount) 
    { 
    DataCount = dataCount; 
    } 
} 

// Now inside your MainPage... 

bool m_keepReading = false; 
bool m_eventHandled = false; 
public event TypedEventHandler<MainPage, DataReceivedEventArgs> DataReceived; 

// Hook this up to (eg) a Button 
private async void StartSockets(object sender, RoutedEventArgs e) 
{ 
    if (!m_eventHandled) 
    DataReceived += (s, args) => Debug.WriteLine(args.DataCount); 
    m_eventHandled = true; 

    m_keepReading = true; 
    DoSocketTestAsync(); 
} 

// Hook this up to (eg) a Button 
private void StopSockets(object sender, RoutedEventArgs e) 
{ 
    m_keepReading = false; 
} 

private async Task DoSocketTestAsync() 
{ 
    var socket = new StreamSocket(); 
    await socket.ConnectAsync(new HostName("www.microsoft.com"), "http"); 
    var writer = new DataWriter(socket.OutputStream); 
    writer.WriteString("GET /en-us HTTP/1.1\r\nHOST: www.microsoft.com\r\n\r\n"); 
    await writer.StoreAsync(); 

    ReadSocketAsync(socket); 
} 

private async void ReadSocketAsync(StreamSocket socket) 
{ 
    while (m_keepReading) 
    { 
    const uint size = 2048; 
    IBuffer buffer = new Windows.Storage.Streams.Buffer(size); 
    buffer = await socket.InputStream.ReadAsync(buffer, size, 
    InputStreamOptions.Partial); 
    var handler = DataReceived; 
    if (handler != null && buffer.Length > 0) 
     handler(this, new DataReceivedEventArgs(buffer.Length)); 
    } 
} 

现在,当你点击“开始”按钮,不会发生这种情况,假设你有一个网络连接,你会看到一些数字开始出现在调试输出窗口。

(另请注意,使用private自动实现的属性并不真正为您购买任何东西;只需将它们设置为字段即可)。

+0

谢谢@peter的回复!我想订阅该事件,但在MSDN文档中没有关于'StreamSocket'对象上的事件的任何信息。正如我在问题中所说的,我试图通过从套接字读取无限的数据来模拟该事件,这是任何平台上的正常行为。而且,正如我所说的,问题是在阅读期间随机冻结UI流程 – alex025

+0

也许我解释了不清楚,但在'StreamSocket'类中没有任何事件,用户代码可以订阅。对于这个问题,没有事件,这可以指示一些数据来自服务器 – alex025

+0

谢谢,但这对我这个问题没有帮助。正如你所看到的,我尝试了一个类似的解决方案,但没有成功。我需要一个选项来监听来自套接字的原始数据,因为这是构建聊天应用程序的唯一方法。如果您知道任何其他方式来持续获取数据并更新相应的用户界面,请编写它。我试图通过直接无限阅读来实现,但正如问题中提到的那样,随机冻结UI流 – alex025