2015-08-18 67 views
1

好的,这个问题需要一些解释,我是一个网络总noob,所以请裸露在我身边。从一个未知长度的Socket接收数据

我设置了使用新的Windows 通用应用架构的客户端 - 服务器网络的Windows 10。其目的是让一台设备充当服务器,其他设备可以连接并发送数据到服务器。至少现在我打算通过局域网来做到这一点。让我们看看一些代码。

我提出的结构是几个类,ServerClient。一台服务器有多个客户端会监听客户端发送的数据,这里是Client

注意:我将提供完整的代码,以便您可以更轻松地进行调试。

public class Client 
{ 
    public StreamSocket Socket { get; internal set; } 
    public bool IsConnected { get; internal set; } 

    public async Task ConnectAsync(string ip, string port = "80") 
    { 
     try 
     { 
      //Create a socket and connect to the IP address. 
      Socket = new StreamSocket(); 

      await Socket.ConnectAsync(new HostName(ip), port); 

      IsConnected = true; 
     } 
     catch (Exception) 
     { 
      IsConnected = false; 

      throw; 
     } 
    } 

    public async void SendDataAsync(string data) 
    { 
     //If we're not connected, then bugger this. 
     if (!IsConnected) 
      throw new InvalidOperationException("The client is not connected to the server, connect first, then try again."); 

     //Send the data. 
     DataWriter stream = new DataWriter(Socket.OutputStream); 

     //Write and commit the data to the server. 
     stream.WriteString(data); 
     await stream.StoreAsync(); 
    } 

    public void Disconnect() 
    { 
     if (IsConnected) 
     { 
      //TODO: Disconnect safely (Still working this one out) 

      //Dispose of the socket. 
      Socket.Dispose(); 
      Socket = null; 
     } 
    } 
} 

我们感兴趣的位是SendDataAsync方法,这就是我们将数据发送到服务器。这里是Server

public class Server 
{ 
    public List<Client> Clients { get; private set; } = new List<Client>(); 

    public StreamSocketListener Listener { get; private set; } 
    public string Port { get; private set; } 

    /// <summary> 
    /// Gets the local IP address of the device. 
    /// </summary> 
    public HostName HostName 
    { 
     get 
     { 
      return NetworkInformation.GetHostNames() 
       .FirstOrDefault(x => x.IPInformation != null 
            && x.Type == HostNameType.Ipv4); 
     } 
    } 

    public Server() 
     : this("80") 
    { } 

    public Server(string port) 
    { 
     if (string.IsNullOrEmpty(port)) 
      throw new ArgumentNullException("port"); 

     Port = port; 
    } 

    public async Task Setup() 
    { 
     Listener = new StreamSocketListener(); 

     //Open a port to listen for connections 
     await Listener.BindServiceNameAsync(Port, SocketProtectionLevel.PlainSocket); 

     Listener.ConnectionReceived += Listener_ConnectionReceived; 
    } 

    private void Listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args) 
    { 
     Client client = new Client() 
     { 
      Socket = args.Socket 
     }; 

     //Add the client to the collection. 
     Clients.Add(client); 

     //Wait for some data. 
     WaitForMessage(client); 
    } 

    private async void WaitForMessage(Client client) 
    { 
     //Open up a stream 
     DataReader stream = new DataReader(client.Socket.InputStream); 

     //Wait for 12 bytes (wtf, what if I don't know for sure how much data is arriving?) 
     await stream.LoadAsync(12); 

     //Get the message that was sent. 
     string message = stream.ReadString(12); 
    } 
} 

我们感兴趣的位是WaitForMessage方法,这是我们正在等待客户端发送一些数据给我们,然后我们会做一些有用的东西吧。

这里是MainPage.xaml.cs代码,使用这些类:

public sealed partial class MainPage : Page 
{ 
    private Server _Server; 
    private Client _Client; 

    public MainPage() 
    { 
     this.InitializeComponent(); 

     SetupServer(); 
     ConnectToServer(); 
    } 

    private async void SetupServer() 
    { 
     //Create the server 
     _Server = new Server(); 

     await _Server.Setup(); 
    } 

    private async void ConnectToServer() 
    { 
     //Create a client and connect to the server. 
     _Client = new Client(); 

     //Note, this may not be your IP address, input your local IP instead (ipconfig in command prompt) 
     await _Client.ConnectAsync("192.168.1.5"); 

     //Send some data to the server. 
     _Client.SendDataAsync("Hello World!"); 
    } 
} 

因此,在实际的问题。下面的代码是给我麻烦:

//Wait for 12 bytes (wtf, what if I don't know for sure how much data is arriving?) 
await stream.LoadAsync(12); 

//Get the message that was sent. 
string message = stream.ReadString(12); 

这里的问题是,它可能不总是12字节被发送到服务器。目前为12,因为这是“Hello World!”的大小。字符串,否则,如果缓冲区较长(大于12),它将永远不会完成接收数据,因为它期望更大的字节数。

就像我提到的,我很新的网络,但是这并不能真正使任何意义,这是我很期待:

  1. 客户端连接到服务器。
  2. 客户端发送一些数据,然后关闭流。
  3. 服务器识别出数据流已关闭(可能是某个事件或某事)并相应地执行操作。

在等待给定字节数的情况下,这些废话都没有。

也许我在看这个问题完全错了,我应该采取不同的方法?

这里有一个想法,我一直在考虑:

  1. 客户端告诉服务器多少字节,它会发送。
  2. 然后,服务器设置流并等待这些字节。
  3. 客户端发送字节。
  4. ...
  5. 利润!

然而,事实是,因为我完全不熟悉这个东西,是有最佳实践办法给客户端 - 服务器架构?

唷,如果你设法阅读所有这些,那么做得很好。我很想看看你们提出了什么。

+0

FWIW,你最后的提纲是我写的数据通信库是如何工作的。没有自动协议来确定消息的长度,您必须提供该消息。 –

回答

0

使用:

DataReader reader = new DataReader(...); 
reader.InputStreamOptions = InputStreamOptions.Partial; 
uint bytesLoaded = await reader.LoadAsync(12); 

然后,LoadAsync()将加载1个12字节之间的东西。如果它加载零字节,则可以假定该流已结束。

还有其他InputStreamOptions,有时你可以混合它们。

相关问题