我有一个客户端服务器应用程序,其中服务器和客户端需要通过网络发送和接收自定义类的对象.我使用TcpClient类来传输数据.我在发送方端序列化对象,并将得到的字节流发送到接收方.但是在接收器中,当我尝试对接收到的字节进行反序列化时,它会抛出序列化异常,详细信息如下:
输入流不是有效的二进制格式.起始内容(以字节为单位)为:0D-0A-00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00 ...
我序列化对象的服务器代码是:
byte[] userDataBytes;
MemoryStream ms = new MemoryStream();
BinaryFormatter bf1 = new BinaryFormatter();
bf1.Serialize(ms, new DataMessage());
userDataBytes = ms.ToArray();
netStream.Write(userDataBytes, 0, userDataBytes.Length);
Run Code Online (Sandbox Code Playgroud)
反序列化的客户端代码是:
readNetStream.Read(readMsgBytes, 0, (int)tcpServer.ReceiveBufferSize);
MemoryStream ms = new MemoryStream(readMsgBytes);
BinaryFormatter bf1 = new BinaryFormatter();
ms.Position = 0;
object rawObj = bf1.Deserialize(ms);
DataMessage msgObj = (DataMessage)rawObj;
Run Code Online (Sandbox Code Playgroud)
请帮我解决这个问题,并建议使用C#中的TcpClient在网络上传输自定义类对象的任何其他方法.
谢谢,拉克什.
ata*_*ata 11
在客户端接收时,您不知道要读取多少数据.您只依赖于ReceiveBufferSize,而您的数据可能会更大或更小.
我认为这里最好的方法是发送4个字节,告诉客户端传入数据的长度:
byte[] userDataLen = BitConverter.GetBytes((Int32)userDataBytes.Length);
netStream.Write(userDataLen, 0, 4);
netStream.Write(userDataBytes, 0, userDataBytes.Length);
Run Code Online (Sandbox Code Playgroud)
在接收端,您首先读取数据长度,然后读取确切的数据量.
byte[] readMsgLen = new byte[4];
readNetStream.Read(readMsgLen, 0, 4);
int dataLen = BitConverter.ToInt32(readMsgLen);
byte[] readMsgData = new byte[dataLen];
readNetStream.Read(readMsgData, 0, dataLen);
Run Code Online (Sandbox Code Playgroud)
事实上,我刚刚意识到,您可能需要做更多的事情来确保您阅读所有数据(只是一个想法,因为我没有尝试过,但只是因为你再次遇到问题,你可以试试这个).
NetworkStream.Read()方法返回一个数字,表示它已读取的数据量.输入数据可能比RecieveBuffer大.在这种情况下,您必须循环,直到您阅读所有数据.你必须做这样的事情:
SafeRead(byte[] userData, int len)
{
int dataRead = 0;
do
{
dataRead += readNetStream.Read(readMsgData, dataRead, len - dataRead);
} while(dataRead < len);
}
Run Code Online (Sandbox Code Playgroud)
看看这段代码.它需要稍微不同的方法.
上面链接给出的例子: - 注意:他面临的另一个问题是他在这里解决了(保持活着).它位于初始示例代码之后的链接中.
要发送的对象类(记住[Serializable]):
[serializable]
public class Person {
private string fn;
private string ln;
private int age;
...
public string FirstName {
get {
return fn;
}
set {
fn=value;
}
}
...
...
public Person (string firstname, string lastname, int age) {
this.fn=firstname;
...
}
}
Run Code Online (Sandbox Code Playgroud)
要发送对象的类:
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
class DataSender
{
public static void Main()
{
Person p=new Person("Tyler","Durden",30); // create my serializable object
string serverIp="192.168.0.1";
TcpClient client = new TcpClient(serverIp, 9050); // have my connection established with a Tcp Server
IFormatter formatter = new BinaryFormatter(); // the formatter that will serialize my object on my stream
NetworkStream strm = client.GetStream(); // the stream
formatter.Serialize(strm, p); // the serialization process
strm.Close();
client.Close();
}
}
Run Code Online (Sandbox Code Playgroud)
接收对象的类:
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
class DataRcvr
{
public static void Main()
{
TcpListener server = new TcpListener(9050);
server.Start();
TcpClient client = server.AcceptTcpClient();
NetworkStream strm = client.GetStream();
IFormatter formatter = new BinaryFormatter();
Person p = (Person)formatter.Deserialize(strm); // you have to cast the deserialized object
Console.WriteLine("Hi, I'm "+p.FirstName+" "+p.LastName+" and I'm "+p.age+" years old!");
strm.Close();
client.Close();
server.Stop();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
27046 次 |
| 最近记录: |