Связь с клиентом и сервером через сокеты

Поэтому я написал код, чтобы я мог общаться с сервером и клиентом.

  • Первый вопрос заключается в том, как сервер определяет, что он общается с реальным клиентом, а не с кем-то еще, кто использует порт. Я слышал, что браузеры проверяют серверы, используя хеширование SHA.
  • Второй вопрос касается наилучшего способа отправки и получения данных в переменных, а также определения того, что есть что, потому что текущий метод разделения данных не кажется очень элегантным.

Код на стороне сервера для получения и отправки данных:

NetworkStream NetStream1 = TCPSocket.GetStream();                       
NetStream.Read(Buffer, 0, Buffer.Length);
ReceivedData = System.Text.Encoding.ASCII.GetString(Buffer);
string[] splitter = ReceivedData.Split('-');
Variable1 = splitter[0];
Variable2 = splitter[1];
//send response
SendBuffer = Encoding.ASCII.GetBytes(ResultINT1+"-"+ResultINT2);
NetStream.Write(SendBuffer, 0, SendBuffer.Length);
NetStream.Flush();

Код клиента для отправки и получения

NetworkStream SendStream = ClientSocket.GetStream();
byte[] SendBuffer = System.Text.Encoding.ASCII.GetBytes(V1+"-"+V2);
SendStream.Write(SendBuffer, 0, SendBuffer.Length);
SendStream.Flush();
//response
SendStream.Read(RecieveBuffer, 0, RecieveBuffer.Length);
string ResultString = System.Text.Encoding.ASCII.GetString(RecieveBuffer);
string[] splitted = ResultString.Split('-');
int R1 = Convert.ToInt32(splitted[0]);
int R2 = Convert.ToInt16(splitted[1]);

person Dinindu Perera    schedule 25.08.2016    source источник
comment
Ваш код не работает. Вы не знаете, сколько байтов было помещено в ReceiveBuffer (вы игнорируете возвращаемое значение из Read, которое могло бы сообщить вам), поэтому небезопасно преобразовывать весь буфер в строку. Нет никакой гарантии, что вызовы Write на одном конце совпадают с вызовами Read на другом.   -  person Damien_The_Unbeliever    schedule 25.08.2016


Ответы (4)


Ваш первый вопрос касается аутентификации, которая является огромной темой и имеет множество возможных реализаций, хотя я не совсем уверен, что вы подразумеваете под «кем-то еще, кто использует порт». Ваш сервер всегда должен быть на одном и том же порту — именно так клиент идентифицирует службу.

Что касается вашего второго вопроса, снова есть много возможностей, но я бы предположил, что самым простым для новичка будет использование XmlSerializer и простого конверта сообщения.

  1. Создайте класс XmlSerializable либо с помощью простых общедоступных свойств, либо, возможно, с помощью XmlElementAttribute, XmlRootAttribute и т. д.
  2. Сериализация в MemoryStream
  3. Запишите байты из потока памяти, завернутые в конверт (см. далее)
  4. Получите полный конверт в массив байтов.
  5. построить MemoryStream из массива байтов
  6. Используйте XmlSerializer для восстановления копии исходного объекта.

Конверт критичен. Самый простой — это просто двоичная длина сериализованного объекта. Большинство протоколов обычно расширяют это с помощью CRC для обработки возможных повреждений, но, поскольку Ethernet использует строгий CRC, а TCP является надежным транспортом (хотя и со слабым CRC), это обычно излишне. Ключевой момент, который упускают новички, заключается в том, что TCP — это протокол потоковой передачи, а не протокол, основанный на сообщениях, поэтому отправитель вполне может сделать одну запись, скажем, 1000 байтов, а получатель получит это как несколько меньших фрагментов. Вот почему вам нужен какой-то способ определить конец сообщения, например, используя длину, и почему получатель должен накапливать полученные фрагменты, пока полное сообщение (и, возможно, часть следующего) не будет получено и не может быть десериализовано.

Это может показаться сложным, но, к сожалению, на уровне TCP проще не бывает :(

person Nick Hounsome    schedule 25.08.2016
comment
Это имеет большой смысл. Я попытался отправить файловый поток, но это было намного медленнее и ненадежнее, чем использование http. - person Dinindu Perera; 26.08.2016

  1. Обеспечьте некоторый механизм аутентификации
  2. Используйте какой-нибудь сериализатор.
person Mauro Sampietro    schedule 25.08.2016
comment
Хм, я полагаю, вы говорите о сериализации объектов. Я изучаю это прямо сейчас. Также можете ли вы указать мне некоторые методы аутентификации, которые будут работать для моей модели? - person Dinindu Perera; 25.08.2016
comment
Вы можете делать наивные вещи, такие как ожидание предопределенного токена от клиента (если не в порядке, тесное общение), или делать сложные вещи, подобные тем, которые описаны в codeproject.com/Articles/14155/ - person Mauro Sampietro; 25.08.2016

Первый вопрос заключается в том, как сервер определяет, что он общается с реальным клиентом, а не с кем-то еще, кто использует порт. Я слышал, что браузеры проверяют серверы, используя хеширование SHA.

Сервер может идентифицировать разных клиентов по их IP-адресам. См. StreamReader.ReadToEnd

Второй вопрос касается наилучшего способа отправки и получения данных в переменных, а также определения того, что есть что, потому что текущий метод разделения данных не кажется очень элегантным.

Это зависит от архитектуры вашего протокола, но переносимый способ обмена значениями в сети состоит в том, чтобы хранить их в текстовом формате (таким образом, нет проблем с последовательностью байтов, размером типа...).

Сказал, что будьте осторожны с вашим разделителем переменных: '-' может быть сложно использовать с отрицательными числами, ' ' или ';' более распространены.

person Mathieu    schedule 25.08.2016

Вы можете захотеть определить какой-либо протокол связи - текстовый протокол был бы наиболее простым для начала - затем вы можете читать и писать "команды" каждую в отдельной строке.

Во-первых, было бы «рукопожатие», когда клиент отправлял что-то вроде «ПРИВЕТ, мой-потрясающий-протокол-v1\n», и сервер отвечал бы аналогичным образом. Таким образом, вы будете уверены, что другой человек является клиентом, который понимает протокол, или вы можете закрыть соединение, которое не реализует протокол.

Тогда может быть какой-то способ отправки значений переменных с помощью таких команд, как «VAR variableName 123.45\n». Вы можете прочитать https://en.wikipedia.org/wiki/Text-based_protocol и см. http://www.ncftp.com/libncftp/doc/ftp_overview.html для вдохновения.

person Šimon Rozsíval    schedule 25.08.2016