Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在C语言中,如何通过网络发送任意对象#_C#_Json_Sockets_Serialization - Fatal编程技术网

C# 在C语言中,如何通过网络发送任意对象#

C# 在C语言中,如何通过网络发送任意对象#,c#,json,sockets,serialization,C#,Json,Sockets,Serialization,我试图使用C#中的套接字通过网络发送任意对象 我已经习惯了Java以及它的工作原理,对C#来说是个新手。 在Java中,我可以创建套接字,创建OutputObjectStream,然后只发送对象。我不需要担心序列化 另一方面,我还有一个套接字,我创建一个ObjectInputStream,读取对象,然后我可以将对象转换回原始类型 Java示例: ObjectInputStream inFromClient = new ObjectInputStream (socket.getInputStrea

我试图使用C#中的套接字通过网络发送任意对象

我已经习惯了Java以及它的工作原理,对C#来说是个新手。 在Java中,我可以创建套接字,创建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)中,据我所知,我需要首先将我的对象转换为JSON,然后转换为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;
publicstatict FromJSON(字符串json){
var ms1=newmemoryStream(Encoding.ASCII.GetBytes(json));
DataContractJsonSerializer DataContractJsonSerializer=新的DataContractJsonSerializer(类型(T));
T sm1=(T)dataContractJsonSerializer.ReadObject(ms1);
返回sm1;
我可能会进行一些优化,创建一个包装类,例如SocketMessage,它将保存枚举方法名,并创建一个string类型的参数来保存JSON字符串。但这真的是这样做的吗

没有像Java中那样的“简单”解决方案吗


它不一定需要是套接字,但这是我所熟悉的。我只需要一台运行服务器的计算机,旁边的一台运行客户端的计算机,这样套接字以外的东西就可以工作。它们将在同一个网络上,所以我想没有花哨的网络。我需要一个开放的双向连接。

如果用c语言,你甚至可以作为JSon解析的结果,通过使用newtonsoft库使用
dynamic
,因此按原样序列化字符串可能是一个选项,在另一方面,您可以通过查看对象上的键属性来了解类型。

您可以做一些事情来简化此操作:

  • 将套接字封装在一个.中,它允许您从/向流进行读/写操作,并使序列化接口更容易一些
  • 用于在json之间序列化对象。我发现这比使用
    DataContractSerializer
    容易得多。此外,您可以:
  • 在序列化对象中包含类型信息。使用Newtonsoft.Json时,如果类型信息包含在序列化中,则在反序列化时无需事先知道类型。例如,设置为
    typenameholling.Object
    。(出于安全原因,您不应将其用于网络外部通信)
综合起来:

// 'client' side
using (var socket = new Socket(SocketType.Stream, ProtocolType.IPv6))
using (var networkStream = new NetworkStream(socket))
using (var writer = new StreamWriter(networkStream))
using (var jsonWriter = new JsonTextWriter(writer)) 
{
    socket.Connect("localhost", 8888);
    var user = new UserInfo { Name = "Jesse de Wit" }; // That's me
    var settings = new JsonSerializerSettings()
    {
        TypeNameHandling = TypeNameHandling.Objects
    };
    var serializer = JsonSerializer.Create(settings);
    serializer.Serialize(jsonWriter, user);
}

// 'server' side
using (var socket = new Socket(SocketType.Stream, ProtocolType.IPv6))
using (var networkStream = new NetworkStream(socket))
using (var reader = new StreamReader(networkStream))
using (var jsonReader = new JsonTextReader(reader))
{
    socket.Accept();
    var settings = new JsonSerializerSettings()
    {
        TypeNameHandling = TypeNameHandling.Objects
    };
    var serializer = JsonSerializer.Create(settings);

    // Note that obj will be a JObject if no type information is included.
    object obj = serializer.Deserialize(jsonReader);
    if (obj is UserInfo user)
    {
        // Jesse de Wit 
        Console.WriteLine(user.Name);
    }
}

如果您有JSON字符串,为什么只通过通道发送该字符串?我需要知道将JSON字符串反序列化为哪种类型的对象。我可以将其作为另一个参数发送。我想知道是否有更简单的方法。您可以使用XML,在这种情况下,根元素名称和命名空间将暗示根对象类型。但是,如果如果允许输入流完全指定类型,则您的应用程序容易受到攻击,如和中所述。(除非
ObjectInputStream
以某种方式清理传入类型,否则您的Java应用程序也可能容易受到攻击。)@ste fu需要考虑的危险信号:BinaryFormatter是过时的、危险的,并且有关于从.NET vNext中正式删除它的讨论“我使用DataContractJsonSerializer,它需要知道,我希望再次释放哪个对象。但我没有这些信息。”-一些花大量时间处理网络代码、序列化、RPC等的人的观点:如果你不知道你期望的是什么,你不应该对它进行反序列化;有很多RPC堆栈等可以让你以安全的方式完成这项工作;坦率地说,这是一个看似复杂的领域——很容易让某些东西正常工作gh是真正危险的(例如:RCE危险)需要考虑的危险信号:BinaryFormatter是过时的、危险的,并且有关于从.NET中正式删除它的讨论vNext@MarcGravell如果使用
typenameholling.Objects
则只需删除即可。@dbc谢谢,在回答中包括您的评论。