好的,这个问题需要一些解释,我是一个网络总noob,所以请裸露在我身边。从一个未知长度的Socket接收数据
我设置了使用新的Windows 通用应用架构的客户端 - 服务器网络的Windows 10。其目的是让一台设备充当服务器,其他设备可以连接并发送数据到服务器。至少现在我打算通过局域网来做到这一点。让我们看看一些代码。
我提出的结构是几个类,Server
和Client
。一台服务器有多个客户端会监听客户端发送的数据,这里是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),它将永远不会完成接收数据,因为它期望更大的字节数。
就像我提到的,我很新的网络,但是这并不能真正使任何意义,这是我很期待:
- 客户端连接到服务器。
- 客户端发送一些数据,然后关闭流。
- 服务器识别出数据流已关闭(可能是某个事件或某事)并相应地执行操作。
在等待给定字节数的情况下,这些废话都没有。
也许我在看这个问题完全错了,我应该采取不同的方法?
这里有一个想法,我一直在考虑:
- 客户端告诉服务器多少字节,它会发送。
- 然后,服务器设置流并等待这些字节。
- 客户端发送字节。
- ...
- 利润!
然而,事实是,因为我完全不熟悉这个东西,是有最佳实践办法给客户端 - 服务器架构?
唷,如果你设法阅读所有这些,那么做得很好。我很想看看你们提出了什么。
FWIW,你最后的提纲是我写的数据通信库是如何工作的。没有自动协议来确定消息的长度,您必须提供该消息。 –