|
Ma'lumotlarni yig'ish strategiyalari
|
bet | 9/11 | Sana | 21.05.2024 | Hajmi | 0,51 Mb. | | #247129 |
Bog'liq Nabijonov Asliddining kurs ishi TCP-da mijoz-server aloqasining eng qiyin qismlaridan biri ma'lumotlarni qabul qilishdir. Bu erda aniq yechim yo'q, lekin bir qator strategiyalar mavjud:
Qancha ma'lumot yuborilishini aniq bilganimizda, qattiq uzunlikdagi buferdan foydalanish
Javob o'lchami haqida ma'lumotni yuborish, qabul qilish bizga kerakli bayt sonini hisoblashni osonlashtiradi.
Javobni tugatish belgisidan foydalanib, biz ma'lumotlarni o'qishni tugatamiz
Ushbu strategiyalarning har qandayidan foydalanish mijoz va server o'rtasidagi o'zaro aloqa uchun oddiy bo'lsa-da, protokolni aniqlashni nazarda tutadi, qachonki mijoz va server yagona qoidalarga muvofiq, oqimdan ma'lumotlarni shakllantiradi, yuboradi va oladi. Ruxsat etilgan bufer versiyasi juda aniq, shuning uchun boshqa ikkita strategiyani ko'rib chiqaylik.
Javobni tugatish belgisidan foydalanish
Quyidagi server kodini aniqlaymiz:
using System.Net;
using System.Net.Sockets;
using System.Text;
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();
// буфер для входящих данных
var buffer = new List();
int bytesRead = '\n';
// считываем данные до конечного символа
while((bytesRead = stream.ReadByte())!='\n')
{
// добавляем в буфер
buffer.Add((byte)bytesRead);
}
var message = Encoding.UTF8.GetString(buffer.ToArray());
Console.WriteLine($"Получено сообщение: {message}");
}
}
finally
{
tcpListener.Stop(); // останавливаем сервер
}
Bu erda usuldan foydalanib, stream.ReadByte()biz oqimdan har bir baytni o'qiymiz. Usulning natijasi baytni int sifatida ko'rsatishdir. Aytaylik, bu yerda xabar markerining oxiri \n belgisi yoki 10 qiymatini ifodalovchi satr tasmasi bo'ladi. Va agar chiziq tasmasi duch kelsa, biz ma'lumotlarni o'qishni tugatamiz va olingan ma'lumotlarni satrga aylantiramiz.
Bunday holda, mijoz xabarning oxiriga \n belgisini qo'shishi kerak bo'ladi:
using System.Net.Sockets;
using System.Text;
using TcpClient tcpClient = new TcpClient();
await tcpClient.ConnectAsync("127.0.0.1", 8888);
// сообщение для отправки
// сообщение завершается конечным символом - \n,
// который символизирует окончание сообщения
var message = "Hello METANIT.COM\n";
// получаем NetworkStream для взаимодействия с сервером
var stream = tcpClient.GetStream();
// считыванием строку в массив байт
byte[] requestData = Encoding.UTF8.GetBytes(message);
// отправляем данные
await stream.WriteAsync(requestData);
Console.WriteLine("Сообщение отправлено");
Garchi bu ma'lum darajada sodda soddalashtirilgan bo'lsa-da, chunki bu holda biz bir qatorli matnni yuborish bilan cheklanamiz. Lekin, aslida, yakuniy markerni aniqlash mantig'i murakkabroq bo'lishi mumkin, ayniqsa marker bir bayt/belgini emas, balki bir nechtasini ifodalasa, lekin umumiy printsip bir xil bo'ladi.
Xabar hajmini sozlash
Keling, quyidagi serverni aniqlaymiz:
using System.Net;
using System.Net.Sockets;
using System.Text;
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();
// буфер для считывания размера данных
byte[] sizeBuffer = new byte[4];
// сначала считываем размер данных
await stream.ReadExactlyAsync(sizeBuffer, 0, sizeBuffer.Length);
// узнаем размер и создаем соответствующий буфер
int size = BitConverter.ToInt32(sizeBuffer, 0);
// создаем соответствующий буфер
byte[] data = new byte[size];
// считываем собственно данные
int bytes = await stream.ReadAsync(data);
var message = Encoding.UTF8.GetString(data, 0, bytes);
Console.WriteLine($"Размер сообщения: {size} байтов");
Console.WriteLine($"Сообщение: {message}");
}
}
finally
{
tcpListener.Stop(); // останавливаем сервер
}
Bunday holda, o'lcham int qiymati bo'ladi, ya'ni 4 bayt qiymati bo'ladi deb taxmin qilamiz. Shunga ko'ra, o'lchamni o'qish uchun biz 4 baytlik bufer yaratamiz va uni stream.ReadExactlyAsyncoqimdan ma'lum miqdordagi baytni o'qiydigan usul yordamida o'qiymiz (bu holda, 4 bayt):
await stream.ReadExactlyAsync(sizeBuffer, 0, sizeBuffer.Length);
Hajmni o'qib chiqqandan so'ng, biz uni statik usul yordamida int ga aylantira olamiz BitConverter.ToInt32(), tegishli uzunlikdagi buferni aniqlaymiz va unga ma'lumotlarni o'qiymiz.
Mijoz tomonida biz quyidagi kodni aniqlaymiz:
using System.Net.Sockets;
using System.Text;
using TcpClient tcpClient = new TcpClient();
await tcpClient.ConnectAsync("127.0.0.1", 8888);
// сообщение для отправки
var message = "Hello METANIT.COM";
// получаем NetworkStream для взаимодействия с сервером
var stream = tcpClient.GetStream();
// считыванием строку в массив байт
byte[] data = Encoding.UTF8.GetBytes(message);
// определяем размер данных
byte[] size = BitConverter.GetBytes(data.Length);
// отправляем размер данных
await stream.WriteAsync(size);
// отправляем данные
await stream.WriteAsync(data);
Console.WriteLine("Сообщение отправлено");
Bu erda teskari jarayon sodir bo'ladi. Birinchidan, biz quyidagi usul yordamida xabar hajmini bayt massiviga olamiz BitConverter.GetBytes():
byte[] size = BitConverter.GetBytes(data.Length);
Biz o'lchamni to'rt bayt sifatida yuboramiz va keyin ma'lumotlarni o'zi yuboramiz:
await stream.WriteAsync(size);
await stream.WriteAsync(data);
N atijada, mijoz ma'lumotlarni yuborgandan so'ng, server konsoli ma'lumotlar hajmini va ma'lumotlarning o'zini ko'rsatadi:
Bir nechta yuborish va qabul qilish
Yuqorida, mijoz yubordi va server faqat bitta xabar oldi. Ammo server alohida qabul qilishi kerak bo'lgan ko'plab xabarlar yuborilsa-chi. Bunday holda, biz yana qandaydir protokolni aniqlashimiz kerak, unga ko'ra server bitta xabar qachon tugashini va mijoz o'zaro aloqani qachon yakunlashini aniqlay oladi. Keling, kichik bir misolni ko'rib chiqaylik. Server quyidagi kodga ega bo'lsin:
using System.Net;
using System.Net.Sockets;
using System.Text;
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();
// буфер для входящих данных
var buffer = new List ();
int bytesRead = 10;
while(true)
{
// считываем данные до конечного символа
while ((bytesRead = stream.ReadByte()) != '\n')
{
// добавляем в буфер
buffer.Add((byte)bytesRead);
}
var message = Encoding.UTF8.GetString(buffer.ToArray());
// если прислан маркер окончания взаимодействия,
// выходим из цикла и завершаем взаимодействие с клиентом
if (message == "END") break;
Console.WriteLine($"Получено сообщение: {message}");
buffer.Clear();
}
}
}
finally
{
tcpListener.Stop();
}
|
| |