NetworkStream и бинарные потоки

Последнее обновление: 06.11.2022

Для чтения и записи бинарных данных, которые представляют примитивные типы, в .NET используются классы BinaryReader и BinaryWriter. Подобно тому, как с их помощью можно писать данные в файл или читать из файла, также можно читать и писать бинарные данные в сетевой поток NetworkStream.

Для отправки бинарных данных в поток объект NetworkStream обертывается в объект класса BinaryWriter, который для отправки данных предоставляет метод Write().

Для чтения бинарных данных из потока объект NetworkStream обертывается в объект класса BinaryReader, который для чтения данных предоставляет ряд методов:

  • ReadBoolean()

  • ReadByte()

  • ReadBytes()

  • ReadChar()

  • ReadChars()

  • ReadDecimal()

  • ReadDouble()

  • ReadHalf()

  • ReadInt16()

  • ReadInt32()

  • ReadInt64()

  • ReadSByte()

  • ReadSingle()

  • ReadString()

  • ReadUInt16()

  • ReadUInt32()

  • ReadUInt64()

Допустим, клиент будет отправлять данные товара, как название товара, производитель, количество и цена. А сервер получит эти данные создаст из них товар и отправит в ответ клиенту сгенерированный идентификатор товара.

Вначале определим код сервера:

using System.Net;
using System.Net.Sockets;

var tcpListener = new TcpListener(IPAddress.Any, 8888);
try
{
    tcpListener.Start();    // запускаем сервер
    Console.WriteLine("Сервер запущен. Ожидание подключений... ");

    while (true)
    {
        // получаем подключение в виде TcpClient
        using var tcpClient = await tcpListener.AcceptTcpClientAsync();
        // получаем объект NetworkStream для взаимодействия с клиентом
        var stream = tcpClient.GetStream();

        // создаем BinaryReader для чтения данных
        using var binaryReader = new BinaryReader(stream);
        // создаем BinaryWriter для отправки данных
        using var binaryWriter = new BinaryWriter(stream);

        var name = binaryReader.ReadString();
        var company = binaryReader.ReadString();
        var count = binaryReader.ReadInt32();
        var price = binaryReader.ReadDecimal();

        string id = Guid.NewGuid().ToString();
        var newProduct = new Product(id, name, company, count, price);
        Console.WriteLine($"Добавлен новый товар: {newProduct}");

        // отправляем клиенту сгенерированный id
        binaryWriter.Write(newProduct.Id);
        binaryWriter.Flush();
    }
}
finally
{
    tcpListener.Stop();
}

record Product(string Id, string Name, string Company, int Count, decimal Price);

Для считывания данных обертываем объект NetworkStream в BinaryReader, а для записи данных - в объект BinaryWriter:

using var binaryReader = new BinaryReader(stream);
using var binaryWriter = new BinaryWriter(stream);

Далее по порядку с помощью методов BinaryWriter считываем присланные данные определенного типа:

var name = binaryReader.ReadString();
var company = binaryReader.ReadString();
var count = binaryReader.ReadInt32();
var price = binaryReader.ReadDecimal();

Далее генерируем Id с помощью функции Guid.NewGuid(), создаем объект Product, выводим его данные на консоль и отправляем в ответ id товара:

string id = Guid.NewGuid().ToString();
var newProduct = new Product(id, name, company, count, price);
Console.WriteLine($"Добавлен новый товар: {newProduct}");

binaryWriter.Write(newProduct.Id);
binaryWriter.Flush();

Клиент

Теперь для этого сервера определим тестовый клиент:

using System.Net.Sockets;

// данные для отправки
string name = "iPhone 14";
string company = "Apple";
int count = 2;
decimal price = 145890.34m;

using TcpClient tcpClient = new TcpClient();
await tcpClient.ConnectAsync("127.0.0.1", 8888);
// получаем NetworkStream для взаимодействия с сервером
var stream = tcpClient.GetStream();
// создаем BinaryReader для чтения данных
using var binaryReader = new BinaryReader(stream);
// создаем BinaryWriter для отправки данных
using var binaryWriter = new BinaryWriter(stream);

// отправляем данные товара
binaryWriter.Write(name);
binaryWriter.Write(company);
binaryWriter.Write(count);
binaryWriter.Write(price);
binaryWriter.Flush();

// считываем сгенерированный на сервере id нового товара
var id = binaryReader.ReadString(); 
Console.WriteLine($"Id нового товара: {id}");

Здесь сначала определяем данные товара для отправки:

string name = "iPhone 14";
string company = "Apple";
int count = 2;
decimal price = 145890.34m;

Как и в коде сервера создаем обертки NetworkStream в виде объектов BinaryReader и BinaryWriter:

using var binaryReader = new BinaryReader(stream);
using var binaryWriter = new BinaryWriter(stream);

Затем отправляем данные с помощью метода Write объекта BinaryWriter:

binaryWriter.Write(name);
binaryWriter.Write(company);
binaryWriter.Write(count);
binaryWriter.Write(price);
binaryWriter.Flush();

Обратите внимание на последовательность отправки - она должна соответствовать последовательности приема на сервере. То есть сервер сначала принимает строку, потом строку, потом int, потом decimal. Соответственно в клиенте сначала отправляем string, потом string, затем int и в конце decimal.

После отправки данных считываем отправленный сервером id товара:

var id = binaryReader.ReadString(); 
Console.WriteLine($"Id нового товара: {id}");

Запустим программы сервера и клиента. Консоль сервера отобразит данные созданного товара:

Сервер запущен. Ожидание подключений...
Добавлен новый товар: Product { Id = 7c036c0d-2682-4f6d-9b7b-7e4869192e21, Name = iPhone 14, Company = Apple, Count = 2, Price = 145890,34 }

а консоль клиента выведет полученный идентификатор товара:

Id нового товара: 7c036c0d-2682-4f6d-9b7b-7e4869192e21
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850