#c# #tcp #streamreader #streamwriter
#c# #tcp #streamreader #streamwriter
Вопрос:
Я понимаю, как отправить объект через TCP-соединение на C #; Я использую StreamWriter
.
Как я могу получить этот объект с другой стороны?
Я пробовал StreamReader
, но он не содержит параметра типа object
.
Как это можно сделать?
Комментарии:
1.Вам следует прочитать некоторые документы о
Serialization
,XmlSerializer
BinaryFormatter
SoapFormatter
DataContractSerializer
JavaScriptSerializer
и т. Д2. StreamReader / Writer предназначены для текста. Если вы не пишете текст, зачем вы пишете текст?
3. Ну, вот что я хочу сделать: я хочу отправить массив изображений: Image[] ImgArr = new ImgArr [2]; object Obj = (object) ImgArr; Я хочу отправить ‘Obj’ и получить его на стороне клиента в качестве другого объекта для использования внутренних изображений…
4. Я сериализовал массив объектов, содержащий 2 массива байтов для двух изображений, это сработало, и я успешно получил оба изображения, но поток слишком медленный…
Ответ №1:
Лучшее решение IMO — использовать BinaryReader
для чтения из потока. Кроме того, вы должны написать поток, используя BinaryWriter
class .
Если ваш объект не относится к одному из базовых типов, вам необходимо выполнить сериализацию перед отправкой его через TCP-соединение.
Комментарии:
1. Ну, вот что я хочу сделать: я хочу отправить массив изображений: Image[] ImgArr = new ImgArr [2]; object Obj = (object) ImgArr; Я хочу отправить ‘Obj’ и получить его на стороне клиента в качестве другого объекта для использования внутренних изображений…
2. Вы должны сериализовать свой объект с помощью BinaryFormatter и десериализовать его с другой стороны: msdn.microsoft.com/en-us/library /…
Ответ №2:
Я действительно могу порекомендовать использовать ProtoBuf для преобразования ваших объектов в / из байтов, которые вы можете отправлять по сети (т.Е. сериализации). Это намного лучше, чем встроенные двоичные сериализаторы (скорость, управление версиями).
Он также имеет дружественные помощники для добавления префикса длины / размера к записанным данным, что полезно, когда вам нужно прочитать данные на принимающей стороне.
Ниже приведен вспомогательный класс, который я использовал для сериализации и сетевого взаимодействия после установления соединения:
public class Messenger
{
private readonly TcpClient client;
private readonly NetworkStream stream;
public IPEndPoint RemoteEndPoint { get { return (IPEndPoint) client.Client.RemoteEndPoint; } }
public Messenger( TcpClient client )
{
this.client = client;
stream = client.GetStream();
}
#region Send and Receive
public TResponse SendReceive<TRequest, TResponse>( TRequest request ) where TRequest : Message where TResponse : Message
{
Send( request );
return Receive<TResponse>();
}
public void Send<TRequest>( TRequest request ) where TRequest : Message
{
using( var ms = new MemoryStream())
{
Serializer.SerializeWithLengthPrefix( ms, request, PrefixStyle.Fixed32 );
stream.Write( ms.GetBuffer(), 0, (int) ms.Length );
stream.Flush();
}
}
public TResponse Receive<TResponse>() where TResponse : Message
{
try
{
return GetMessage<TResponse>();
}
catch (Exception ex)
{
if (ex is IOException || ex is InvalidOperationException)
{
stream.Dispose();
}
throw;
}
}
#endregion
#region Helpers
private TMessage GetMessage<TMessage>() where TMessage : Message
{
int messageLength = BitConverter.ToInt32(GetBytes(stream, 4), 0);
byte[] data = GetBytes(stream, messageLength);
using (var ms = new MemoryStream(data))
{
return Serializer.Deserialize<TMessage>(ms);
}
}
private static byte[] GetBytes(NetworkStream stream, int length)
{
int bytesRequired = length;
int bytesRead = 0;
var bytes = new byte[length];
do
{
while( !stream.DataAvailable )
Thread.Sleep( 100 );
int read = stream.Read(bytes, bytesRead, bytesRequired);
bytesRequired -= read;
bytesRead = read;
}
while (bytesRequired > 0);
return bytes;
}
#endregion
}
Примечание: класс Serializer взят из библиотеки ProtoBuf.
Комментарии:
1. Ну, вот что я хочу сделать: я хочу отправить массив изображений: Image[] ImgArr = new ImgArr [2]; object Obj = (object) ImgArr; Я хочу отправить ‘Obj’ и получить его на стороне клиента в качестве другого объекта для использования внутренних изображений…
2. Затем создайте класс со свойством Images (типа Image[] ), украсьте его необходимыми атрибутами ProtoBuf (изучите документы для получения справки по этому вопросу или выполните поиск в StackOverflow) и используйте метод Send для его передачи (и, очевидно, получения на принимающей стороне).).
Ответ №3:
Если вы не хотите или не можете использовать BinaryFormatter, вам придется десериализовать объект yoursekf
Модифицированный пример из msdn для двоичного форматирования:
Допустим, у вас есть модель:
[Serializable] //you could also make the class implement ISerializable
class SomeModel
{
public String Name
{
get;
set;
}
}
у вас есть свой сетевой поток:
NetworkStream ns;
базовый пример того, как вы выполняете часть сериализации:
void Serialize()
{
SomeModel myModel = new SomeModel()
{
Name = "mooo"
};
// Construct a BinaryFormatter and use it to serialize the data to the stream.
BinaryFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(ns, myModel);
}
catch (SerializationException e)
{
throw e;
}
}
а что касается десериализации
void Deserialize()
{
SomeModel myModel;
try
{
BinaryFormatter formatter = new BinaryFormatter();
// Deserialize the object from the stream and
// assign the reference to the local variable.
myModel = (SomeModel) formatter.Deserialize(ns);
}
catch (SerializationException e)
{
throw e;
}
}
Есть одна вещь, о которой вы должны позаботиться.
Вы должны знать, что при десериализации вы не можете просто вставить в него поток и получить что-то обратно, вы должны знать, что то, что вы собираетесь прочитать, на самом деле является сериализованным SomeModel-классом.
Я не знаю, как выглядит ваш код, поэтому я не знаю, является ли это проблемой или нет, и если да, то как ее избежать.
В любом случае, вашим вторым выбором было бы использовать BinaryReader. Вам нужно будет создать экземпляр вашего объекта и прочитать данные вручную.
using(BinaryWriter writer =
new BinaryWriter(ns))
{
binWriter.Write(myModel.Name);
}
чтение:
using(BinaryReader reader =
new BinaryReader(ns))
{
try
{
SomeModel myModel = new SomeModel();
myModel.Name = binReader.ReadString();
}
// If the end of the stream is reached before reading
// the four data values, ignore the error and use the
// default settings for the remaining values.
catch(EndOfStreamException e)
{
Console.WriteLine("{0} caught and ignored. "
"Using default values.", e.GetType().Name);
}
}
Комментарии:
1. Ну, вот что я хочу сделать: я хочу отправить массив изображений: Image[] ImgArr = new ImgArr [2]; object Obj = (object) ImgArr; Я хочу отправить ‘Obj’ и получить его на стороне клиента в качестве другого объекта для использования внутренних изображений…