发送复合型数据: 除了传输数值型数据,我们更多的是传输复合型数据,如字符,数值,bool等等。是否存在简单办法发送复合型数据呢?
可以建立一个类, class Employee { public int EmployeeID;public int LastNameSize;public string LastName;public int FirstNameSize;public string FirstName;public int YearsService;public double Salary;public int size;}
public byte [] GetBytes() { //字节数组,将Empolyee转换为字节数组的容器byte[] data = new byte[1024];//位置标示int place = 0;//转换Int32 类型的数据为Byte[],加入到data中Buffer.BlockCopy(BitConverter.GetBytes(EmployeeID), 0, data, place, 4);//位移+4place += 4;//将字符LastName的长度转换为字节数组,加入到dataBuffer.BlockCopy(BitConverter.GetBytes(LastName.Length), 0, data, place, 4);//增加位移place += 4;//把字符转换为字节数组,加入到DataBuffer.BlockCopy(Encoding.ASCII.GetBytes(LastName), 0,data, place, LastName.Length);//增加相应位移place += LastName.Length;//将字符FirstName的长度转换为字节数组,加入到DataBuffer.BlockCopy(BitConverter.GetBytes(FirstName.Length),0, data, place, 4);//增加位移place += 4;//把字符转换为字节数组,加入到dataBuffer.BlockCopy(Encoding.ASCII.GetBytes(FirstName), 0,data, place, FirstName.Length);//增加位移place += FirstName.Length;//转换YearService为byte[],加入到dataBuffer.BlockCopy(BitConverter.GetBytes(YearsService), 0, data, place, 4);//增加位移place += 4;//转换类型为double的Salary为Byte[],加入到dataBuffer.BlockCopy(BitConverter.GetBytes(Salary), 0, data, place, 8);//增加位移place += 8;//获取Employee类转换为字节数组的实际长度size = place;return data;}
可以这样理解网络中传输的字节数组,网络就像是有2条铁轨的道路,允许2列火车同时运行,而火车由车头,车厢组成,车厢又分为硬座车型,软座车箱,硬卧车厢,软卧车厢,餐车,邮件车厢等,每个数据类型的字节数组,对应上面的车箱,因为特定乘客要到特定车厢,所以特定的数组也要在发送的总的数组的特定位置。
通过网络,我们说到了这个数组,怎样还原呢?
首先,我们要知道Employee 类的结构,然后,可以 public Employee( byte [] data) { int place = 0;EmployeeID = BitConverter.ToInt32(data, place);place += 4;LastNameSize = BitConverter.ToInt32(data, place);place += 4;LastName = Encoding.ASCII.GetString(data, place, LastNameSize);place = place + LastNameSize;FirstNameSize = BitConverter.ToInt32(data, place);place += 4;FirstName = Encoding.ASCII.GetString(data, place, FirstNameSize);place += FirstNameSize;YearsService = BitConverter.ToInt32(data, place);place += 4;Salary = BitConverter.ToDouble(data, place);}
using System; using System.Net; using System.Net.Sockets; class EmployeeClient { public static void Main(){ Employee emp1 = new Employee();Employee emp2 = new Employee();TcpClient client;emp1.EmployeeID = 1;emp1.LastName = "Blum";emp1.FirstName = "Katie Jane";emp1.YearsService = 12;emp1.Salary = 35000.50;emp2.EmployeeID = 2;emp2.LastName = "Blum";emp2.FirstName = "Jessica";emp2.YearsService = 9;emp2.Salary = 23700.30;try{ client = new TcpClient("127.0.0.1", 9050);} catch (SocketException){ Console.WriteLine("Unable to connect to server");return;}NetworkStream ns = client.GetStream();byte[] data = emp1.GetBytes();int size = emp1.size;byte[] packsize = new byte[2];Console.WriteLine("packet size = {0}", size);packsize = BitConverter.GetBytes(size);ns.Write(packsize, 0, 2);ns.Write(data, 0, size);ns.Flush();data = emp2.GetBytes();size = emp2.size;packsize = new byte[2];Console.WriteLine("packet size = {0}", size);packsize = BitConverter.GetBytes(size);ns.Write(packsize, 0, 2);ns.Write(data, 0, size);ns.Flush();ns.Close();client.Close();}}
using System; using System.Net; using System.Net.Sockets; class EmployeeSrvr { public static void Main(){ byte[] data = new byte[1024];TcpListener server = new TcpListener(9050);server.Start();TcpClient client = server.AcceptTcpClient();NetworkStream ns = client.GetStream();byte[] size = new byte[2];int recv = ns.Read(size, 0, 2);int packsize = BitConverter.ToInt16(size, 0);Console.WriteLine("packet size = {0}", packsize);recv = ns.Read(data, 0, packsize);Employee emp1 = new Employee(data);Console.WriteLine("emp1.EmployeeID = {0}", emp1.EmployeeID);Console.WriteLine("emp1.LastName = {0}", emp1.LastName);Console.WriteLine("emp1.FirstName = {0}", emp1.FirstName);Console.WriteLine("emp1.YearsService = {0}", emp1.YearsService);Console.WriteLine("emp1.Salary = {0}\n", emp1.Salary);size = new byte[2];recv = ns.Read(size, 0, 2);packsize = BitConverter.ToInt16(size, 0);data = new byte[packsize];Console.WriteLine("packet size = {0}", packsize);recv = ns.Read(data, 0, packsize);Employee emp2 = new Employee(data);Console.WriteLine("emp2.EmployeeID = {0}", emp2.EmployeeID);Console.WriteLine("emp2.LastName = {0}", emp2.LastName);Console.WriteLine("emp2.FirstName = {0}", emp2.FirstName);Console.WriteLine("emp2.YearsService = {0}", emp2.YearsService);Console.WriteLine("emp2.Salary = {0}", emp2.Salary);ns.Close();client.Close();server.Stop();}}
现在我们把复合类型转换为单一类型,通过网络发送到目的地,然后又重新组合起来,同前面说的搬运埃菲尔铁塔,用的是相同的道理。
我们经常遇到的另一种情况是传送文件,文件可以方便的转换为字节数组,通过网络传输,要注意:
1.因为MTU的原因,每次传输的最大字节数组的长度为1024,不要大于这个值,如果文件较大,可以每次传输1024个字节,接收方按顺序收到后,在还原成原始文件。2.可以使用每次发送固定长度字节的办法,在获取文件长度后,每次发送固定长度,直到发完。 关于在网络中传输数据,就写到这里,如果有问题,请给我留言。 谢谢浮云。 MTU(Maximum Transmission Unit) 最大传输单元: 经网络发送的单一包可容纳的最大数据量。每种网络技术都定义一个MTU(以太网的MTU是1500个字节)。 以太网和802.3对数据帧的长度都有一个限制,其最大值分别是1500和1492字节。链路层的这个特性称作MTU,最大传输单元。不同类型的网络大多数都有一个上限。 如果IP层有一个数据报要传,而且数据的长度比链路层的MTU还大,那么IP层就需要进行分片(fragmentation),把数据报分成若干片,这样每一片都小于MTU。 网络传输文件,因为在IP层作了处理,所以我们不必再做处理。可以发送大于1024字节的数据。 关于“是不是我们就不需要关心每次发送的包大小了呢? ”,发送文件的大小取决于内部消息缓冲区或者网络的限制,因为网络可以将数据分割,所以只需要考虑有没有传送时间的限制,如Http上传的时间限制,另外,系统的内部缓冲区的大小默认是8192字节,即8K,所以发送文件时,按照8K拆分发送