1

Тема: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

Хай. От хочу спробувати цей протокол і написати на ньому сервер. Ну сервер, здається, є, звісно, він найпростіший, я ж тільки тренуюся. Клієнт теж є, але я не можу зрозуміти, як він має приймати дані? Я не можу запустити метод BeginReceiveFrom, тому що перед ним потрібно викликати метод Bind, окей, я викликаю Bind і запускаю один екземпляр клієнта - все працює, дані на сервер надходять. Але якщо я намагаюсь запустит ще один клієнт, то вистрілює помилка, що типу можна лише один раз викликати Bind для одної адреси. Як мені бути? Ось код клієнту

 public static class Client
    {
        private static string host = "127.0.0.1";
        private static int portReceive = 9061, portSend = 9060;

        private static Socket socket = new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
        private static byte[] buffer=new byte[1024];
        private static IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(host),portSend);
        private static EndPoint endPointSend = (EndPoint)ipEndPoint;
        public static EndPoint endPointReceive = new IPEndPoint(IPAddress.Parse(host),portReceive);

        public static void Start()
        {
            socket.Bind(endPointReceive);
            socket.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref endPointReceive, new AsyncCallback(ReceiveCallback), socket);
        }

        private static void ReceiveCallback(IAsyncResult ar)
        {
            int n = socket.EndReceive(ar);
            string str = Encoding.UTF8.GetString(buffer,0,n);
            Console.WriteLine(str);
            socket.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None,ref endPointReceive, new AsyncCallback(ReceiveCallback), socket);
        }

        public static void Send(string message)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(message);

            socket.BeginSendTo(buffer, 0, buffer.Length, SocketFlags.None, endPointSend, new AsyncCallback(SendCallback),
                socket);
        }

        private static void SendCallback(IAsyncResult ar)
        {
         //   Socket socket1 = (Socket) ar;
            int n = socket.EndSendTo(ar);
        }
    }

2

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

ааа, розібрався, там просто спочатку треба відправити щось, а потім можна приймати, і Bind непотрібен.

3

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

Реєструйте на кількох портах і повідомляйте серверу про різні порти.

4

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

koala написав:

Реєструйте на кількох портах і повідомляйте серверу про різні порти.

да вже все ок, я ж написав, та й той варіант Ваш був би взагалі того, тому що я ж планую запускати не два і не три клієнта, а десь 10, аби перевірити працездатність цього всього

5

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

в мене є декілька уточнюючих питань по UDP
Я ось знаю кілька істин про UDP - він не потребує з'єднання, він не гарантує доставку, він не гарантує цілісність даних і їх послідовність, але він швидкий.
Із з'єднанням все зрозуміло, просто відправляється пакет, а далі всі завдання прийняття неприйняття і т.д. лежать на іншій стороні.
Він не гарантує доставку - це як? Тобто я можу відправляти багато пребагато повідомлень, а сервер навіть не дізнається, що я їх взагалі відправляв?
Немає гарантії цілісності. Це, наприклад, я відправляю 20 байт, а приходить 18? Тоді куди діваються два байти? І в якій частині 20-ти байт ці два байти зникають? На початку? Наприкінці? У будь-якій?
Неправильна послідовність. Я так розумію, на увазі маються пакети? А що таке пакети в UDP? Припустимо , у мене є буфер з байтами, і я відправляю його на сервер

byte[] buffer = new byte[1024];
Send(buffer);

В цьому випадку у мене:
a) 1024 пакетів, тому що 1024 байта, і всі вони можуть прийти повністю перемішаними?
b) 1024 * 8 пакетів, тому що дані передаються побітно?
с) 1 пакет довжиною в 1024 байта, і якщо я зроблю так

byte[] buffer1 = new byte[1024];
byte[] buffer2 = new byte[512];
Send(buffer1);
Send(buffer2);

то вся невпорядкованість полягає в тому, що спочатку може прийти buffer2, а потім buffer1?

6

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

FakiNyan написав:

Він не гарантує доставку - це як? Тобто я можу відправляти багато пребагато повідомлень, а сервер навіть не дізнається, що я їх взагалі відправляв?

Я б не сказав краще.

FakiNyan написав:

Немає гарантії цілісності. Це, наприклад, я відправляю 20 байт, а приходить 18?

В принципі, можливо і таке. Але частіше замість 12345 буде приходити 12545. Щоправда, "частіше" - це один раз на мільйони, якщо зв'язок нормальний. От якщо в поле "довжина" буде помилка - тоді буде втрата частини пакета

FakiNyan написав:

Неправильна послідовність. Я так розумію, на увазі маються пакети?

Так, саме вони.

FakiNyan написав:

вся невпорядкованість полягає в тому, що спочатку може прийти buffer2, а потім buffer1?

В точку.

Просте пояснення: якщо вам треба точно знати, чи дані коректні, треба додати в пакети контрольну суму.
Якщо треба точно знати, який пакет пішов раніше, треба додати в пакети лічильник.
Якщо певний час немає пакету, а ви знаєте, що він мав прийти, або він надійшов некоректним, і він вам потрібен, треба надіслати запит на повторення.
Якщо ви все це зробите, то це буде велосипедний TCP.

Подякували: FakiNyan, Torbins2

7

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

koala написав:
FakiNyan написав:

Він не гарантує доставку - це як? Тобто я можу відправляти багато пребагато повідомлень, а сервер навіть не дізнається, що я їх взагалі відправляв?

Я б не сказав краще.

FakiNyan написав:

Немає гарантії цілісності. Це, наприклад, я відправляю 20 байт, а приходить 18?

В принципі, можливо і таке. Але частіше замість 12345 буде приходити 12545. Щоправда, "частіше" - це один раз на мільйони, якщо зв'язок нормальний. От якщо в поле "довжина" буде помилка - тоді буде втрата частини пакета

FakiNyan написав:

Неправильна послідовність. Я так розумію, на увазі маються пакети?

Так, саме вони.

FakiNyan написав:

вся невпорядкованість полягає в тому, що спочатку може прийти buffer2, а потім buffer1?

В точку.

Просте пояснення: якщо вам треба точно знати, чи дані коректні, треба додати в пакети контрольну суму.
Якщо треба точно знати, який пакет пішов раніше, треба додати в пакети лічильник.
Якщо певний час немає пакету, а ви знаєте, що він мав прийти, або він надійшов некоректним, і він вам потрібен, треба надіслати запит на повторення.
Якщо ви все це зробите, то це буде велосипедний TCP.

хД ну я то все пойняв. Але мені велосипедного ТСР поки що не треба, може потім...

8

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

Як гадаєте, оце норм структура для пакету? http://не-дійсний-домен/82v7B.jpg
L (ushort) - довжина всього пакету, щоб перевіряти, чи він цілий дійшов
id (ushort) - id клієнта, щоб розуміти, що за клієнт це прислав
№ (long) - номер пакету, щоб відкидати ті, котрі вже застарілі
LD (ushort) - довжина даних
всього заголовок займає 14 байт, це норм?

9

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

Я б добавив контрольну суму (геш) вмісту пакета

10

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

Три рази довжину передавати (один раз в заголовку UDP і ще два рази всередині) - чи не замало? Для надійності треба разів так 5-6 :)
Викиньте довжини (обидві), додайте хеш. UDP і так знає, якої довжини пакет, тобто L; а LD завжди лінійно залежить від L.

11

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

koala написав:

Три рази довжину передавати (один раз в заголовку UDP і ще два рази всередині) - чи не замало? Для надійності треба разів так 5-6 :)
Викиньте довжини (обидві), додайте хеш. UDP і так знає, якої довжини пакет, тобто L; а LD завжди лінійно залежить від L.

ааа, тобто це тільки в TCP, якщо відправляти два повідомлення 20 і 30 байт, то може прийти одне 50 байт? А в UDP скільки відправив стільки й приходить?

12

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

TCP - Transmission Control Protocol, TCP (укр. Прото́кол керува́ння переда́чею)
UDP - User Datagram Protocol (укр. Протокол дейтаграм користувача)
Бачите? TCP керує передачею, а скільки там пакетів - не його справа. Він дає файлоподібний інтерфейс (сокет), з якого можна читати потік. А UDP - це протокол дейтаграм, а дейтаграма - це і є пакет.
Насправді пакети UDP теж можуть розбиватися протоколами нижчого рівня (зокрема, IP). Це можна заборонити (читайте документацію), але тоді надто великі пакети будуть не доходити. Втім, це вже не ваша проблема, як там воно насправді бігає. Ідея в тому, що TCP - стабільний потік (з затримками), а UDP - окремі пакети. Цього вам поки вистачить.

13

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

koala написав:

TCP - Transmission Control Protocol, TCP (укр. Прото́кол керува́ння переда́чею)
UDP - User Datagram Protocol (укр. Протокол дейтаграм користувача)
Бачите? TCP керує передачею, а скільки там пакетів - не його справа. Він дає файлоподібний інтерфейс (сокет), з якого можна читати потік. А UDP - це протокол дейтаграм, а дейтаграма - це і є пакет.
Насправді пакети UDP теж можуть розбиватися протоколами нижчого рівня (зокрема, IP). Це можна заборонити (читайте документацію), але тоді надто великі пакети будуть не доходити. Втім, це вже не ваша проблема, як там воно насправді бігає. Ідея в тому, що TCP - стабільний потік (з затримками), а UDP - окремі пакети. Цього вам поки вистачить.

окєй, а як той хеш або контрольну суму взяти? Я от думав, що це якась стандартна операція і вже все є готове, треба лише метод викликати, але коли примінив GetHashCode() до масиву байтів, то він дає різний результат в випадку одного і того ж самого масиву

14

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

Писати свій хеш (GetHashCode працює тільки всередині однієї програми і залежить від адрес).
Власне, тут буде достатньо проXORити все, розбите на групи по 2 байти - вам же тільки помилки шукати, а не злам...

15

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

koala написав:

Писати свій хеш (GetHashCode працює тільки всередині однієї програми і залежить від адрес).
Власне, тут буде достатньо проXORити все, розбите на групи по 2 байти - вам же тільки помилки шукати, а не злам...

щось я ото туплю, на виході має бути теж масив байт? А довжина тоді буде як половина довжини пакету?

16

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

Був набір байтів: 1 3 4 6 8
Розбиваємо на групи по 2: 13 46 80 (доповнили 0)
XOR-имо: 13⊕46⊕80 = HASH
Ось цей хеш і пишемо.
До речі, якщо так зробити з початковим пакетом, але хеш поставити 0, а потім вставити хеш, то сума стане 0.

17

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

koala написав:

Був набір байтів: 1 3 4 6 8
Розбиваємо на групи по 2: 13 46 80 (доповнили 0)
XOR-имо: 13⊕46⊕80 = HASH
Ось цей хеш і пишемо.
До речі, якщо так зробити з початковим пакетом, але хеш поставити 0, а потім вставити хеш, то сума стане 0.

а ось ці 13 46 80 - це масиви байт чи що? бо я щось отак пробую зробити

byte[] GetHash(byte[] data)
        {
            int lenght = data.Length;
            byte[] hash=new byte[2];
            for (int i = 0; i < lenght; i+=2)
            {
                hash ^= new byte[] {data[i], data[i + 1]};
            }
            return hash;
        }

а воно каже, шо не мона зробити ^ між масивами байт

18

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

Ні, я мав на увазі числа. Десь так:

ushort GetHash(byte[] data)
{
  int length = data.Length;
  ushort hash=0;
  for (int i = 0; i < length - 1; i += 2) //на випадок непарної довжини
  {
    hash ^= BitConverter.ToUInt16( data, i );
  }
  if( length % 2 != 0 )
    hash ^= data[ length - 1 ] << 8;
  return hash;
}

Хм... а шарп допускає такі операції з масивами, як у вас?

19

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

koala написав:

Ні, я мав на увазі числа. Десь так:

ushort GetHash(byte[] data)
{
  int length = data.Length;
  ushort hash=0;
  for (int i = 0; i < length - 1; i += 2) //на випадок непарної довжини
  {
    hash ^= BitConverter.ToUInt16( data, i );
  }
  if( length % 2 != 0 )
    hash ^= data[ length - 1 ] << 8;
  return hash;
}

Хм... а шарп допускає такі операції з масивами, як у вас?

які?

20

Re: Поясніть за UDP-протокол, як запустити декілька клієнтів на одному ПК?

Такі:

 
byte[] hash=new byte[2];
hash ^= new byte[] {data[i], data[i + 1]};