【发布时间】:2019-06-28 09:49:56
【问题描述】:
我正在尝试使用 C# 中的套接字通过网络发送任意对象。
我已经习惯了 Java 以及它是如何工作的,对于 C# 来说是新手。 在 Java 中,我可以创建一个 Socket,创建一个 OutputObjectStream,然后发送对象。我不需要关心序列化。
另一方面,我也有一个套接字,我创建一个 ObjectInputStream,读取对象,然后我可以将对象转换回原始类型。
Java 示例:
ObjectInputStream inFromClient = new ObjectInputStream (socket.getInputStream());
Object read = inFromClient.readObject();
if(read instanceof bool) {
// cast read to bool, and call relevant method
} else if(read instanceof UserInfo) {
// cast read to UserInfo...
} else if(read instanceof CarInfo) {
// cast read to CarInfo...
}
但是在 C# 中(我使用的是 JSON),据我所知,我需要先将我的 Object 转换为 JSON,然后再转换为 byte[] 然后发送它。另一方面,我从 byte[] 转换为字符串,然后再转换为 JSON。我使用 DataContractJsonSerializer,它需要知道我希望再次取出哪个对象。但我没有那个信息。
我目前的解决方案是每次发送两次。发送的第一个对象是方法名称(表示为枚举),发送的第二个对象是实际对象。根据第一个收到的方法名称,我知道第二个对象应该是什么,并且可以告诉我的 JSON 序列化程序包装器。像这样的:
public static T FromJSON<T>(string json) {
var ms1 = new MemoryStream(Encoding.ASCII.GetBytes(json));
DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(T));
T sm1 = (T) dataContractJsonSerializer.ReadObject(ms1);
return sm1;
我可能会优化一点,并创建一个包装类,例如SocketMessage,它将保存枚举方法名称,以及一个字符串类型的参数来保存 JSON 字符串。但这真的是这样做的方法吗?
没有像 Java 那样“简单”的解决方案吗?
不一定非得是 Sockets,但这是我所熟悉的。我只需要一台运行服务器的计算机,以及一台运行客户端的计算机,所以除了 Sockets 之外的其他东西也可以工作。他们将在同一个网络上,所以我认为没有花哨的网络。我需要一个开放的双向连接。
【问题讨论】:
-
如果你有 JSON 字符串,为什么你只是通过通道发送字符串?
-
我需要知道将 JSON 字符串反序列化成什么样的对象。我可以把它作为另一个论点。我想知道是否有更简单的方法。
-
你可以使用 XML,在这种情况下,根元素名称和命名空间将暗示根对象类型。但是,如果您允许输入流完全指定类型,您的应用程序很容易受到小工具注入攻击,如TypeNameHandling caution in Newtonsoft Json 和blackhat.com/docs/us-17/thursday/… 中所述。 (除非
ObjectInputStream以某种方式清理传入的类型,否则您的 Java 应用程序也可能容易受到攻击。) -
@ste-fu 需要考虑的危险信号:BinaryFormatter 已过时、危险,并且有关于正式将其从 .NET vNext 中删除的讨论
-
“我使用 DataContractJsonSerializer,它需要知道我希望再次取出哪个对象。但我没有那个信息。” - 来自花费大量时间处理网络代码、序列化、RPC 等的人的意见:如果你不知道你在期待什么,你不应该反序列化它;有很多 RPC 堆栈等可以让您以安全的方式执行此操作;坦率地说,这是一个看似复杂的领域——很容易让某些东西运行得足够好,从而成为真正的危险(例如:RCE 危险)
标签: c# json sockets serialization