C#网络编程之TCP(三)
一、数据的发送规则
在上一篇章说道,tcp的数据传输在网络信道中是以字节的方式传输的,接受方并不知道数据的具体长度,每次按照固定的长度进行读取,那么在读取数据的时候会出现和我们想象的不一样的结果。
服务端
const string ip = "127.0.0.1"; const int port = 10002; // 建立服务器 Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); EndPoint point = new IPEndPoint(IPAddress.Parse(ip), port); socket.Bind(point); socket.Listen(); Console.WriteLine("服务器启动,等待连接..."); // 监听客户端发起连接 Socket conn = socket.Accept(); Console.WriteLine("有客户端连接..."); // 发送数据 string outputMsg1 = "Hello World!"; string outputMsg2 = "你好世界"; conn.Send(Encoding.UTF8.GetBytes(outputMsg1)); conn.Send(Encoding.UTF8.GetBytes(outputMsg2)); Console.WriteLine(">>: " + outputMsg1); Console.WriteLine(">>: " + outputMsg2); // 关闭连接 conn.Close();
客户端
const string ip = "127.0.0.1"; const int port = 10002; // 连接至服务器 Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); EndPoint point = new IPEndPoint(IPAddress.Parse(ip), port); socket.Connect(point); Console.WriteLine("客户端启动,连接到服务器..."); // 接收数据 byte[] bytes = new byte[1024]; int len = socket.Receive(bytes); string inputMsg1 = Encoding.UTF8.GetString(bytes, 0, len); Console.WriteLine("<<: " + inputMsg1); // 接收数据 byte[] bytes2 = new byte[1024]; int len2 = socket.Receive(bytes2); string inputMsg2 = Encoding.UTF8.GetString(bytes2, 0, len2); Console.WriteLine("<<: " + inputMsg2); // 关闭连接 socket.Close();
客户端连上服务端后,服务端连续发送了2条信息:"Hello World!","你好世界";客户端也连续接收了2次数据。从结果上看,客户端可能第一次就接收到了全部的数据,或是接收到的数据不完整。
二、数据的完整性
该怎么解决上述的问题呢?这就需要我们自己定制新的规则。
1.发送方:byte[4] + byte[N]
2.接收方:先接收4字节得知长度信息N,在接收N字节
服务端
const string ip = "127.0.0.1"; const int port = 10002; // 建立服务器 Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); EndPoint point = new IPEndPoint(IPAddress.Parse(ip), port); socket.Bind(point); socket.Listen(); Console.WriteLine("服务器启动,等待连接..."); // 监听客户端发起连接 Socket conn = socket.Accept(); Console.WriteLine("有客户端连接..."); // 发送数据 string outputMsg1 = "Hello World!"; string outputMsg2 = "你好世界"; byte[] buf = new byte[4]; // 先发送内容的长度 ConvertIntToByteArray(Encoding.UTF8.GetBytes(outputMsg1).Length, ref buf); conn.Send(buf); // 再发送内容 conn.Send(Encoding.UTF8.GetBytes(outputMsg1)); // 先发送内容的长度 ConvertIntToByteArray(Encoding.UTF8.GetBytes(outputMsg2).Length, ref buf); conn.Send(buf); // 再发送内容 conn.Send(Encoding.UTF8.GetBytes(outputMsg2)); Console.WriteLine(">>: " + outputMsg1); Console.WriteLine(">>: " + outputMsg2); // 关闭连接 conn.Close(); static bool ConvertIntToByteArray(Int32 m, ref byte[] arry) { if (arry == null) return false; if (arry.Length < 4) return false; arry[0] = (byte)(m & 0xFF); arry[1] = (byte)((m & 0xFF00) >> 8); arry[2] = (byte)((m & 0xFF0000) >> 16); arry[3] = (byte)((m >> 24) & 0xFF); return true; }
客户端
const string ip = "127.0.0.1"; const int port = 10002; // 连接至服务器 Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); EndPoint point = new IPEndPoint(IPAddress.Parse(ip), port); socket.Connect(point); Console.WriteLine("客户端启动,连接到服务器..."); // 接收数据 byte[] bytes = new byte[4]; // 先获取内容长度 socket.Receive(bytes); int inputLength1 = BitConverter.ToInt32(bytes, 0); byte[] msgBytes1 = new byte[inputLength1]; // 再获取内容 socket.Receive(msgBytes1); string inputMsg1 = Encoding.UTF8.GetString(msgBytes1, 0, inputLength1); Console.WriteLine("<<: " + inputMsg1); // 接收数据 // 先获取内容长度 socket.Receive(bytes); int inputLength2 = BitConverter.ToInt32(bytes, 0); byte[] msgBytes2 = new byte[inputLength2]; // 再获取内容 socket.Receive(msgBytes2); string inputMsg2 = Encoding.UTF8.GetString(msgBytes2, 0, inputLength2); Console.WriteLine("<<: " + inputMsg2); // 关闭连接 socket.Close();