Menci Lucio Ответов: 2

Замедление в соединениях tcpclient


Привет,

Я написал клиент-серверное приложение, я использовал TcpServer и TcpClient объекты, чтобы включить эту связь.

На стороне сервера у меня не было никаких проблем. Кажется, что когда клиент выполняет запрос, сервер отвечает так быстро. Но на стороне клиента есть небольшое замедление при инициализации TcpClient.

Как использовать одну инициализацию TcpClient для всех запросов?

Спасибо!

Что я уже пробовал:

Я написал этот метод:
TcpClient TcpClient = null;
NetworkStream TcpClientStream = null;
public string SendRequest(string command, out string response)
{
   TcpClient = new TcpClient(TcpAddress, TcpPort);      // [1]
   TcpClientStream = TcpClient.GetStream();             // [2]
   byte[] msg = Encoding.ASCII.GetBytes(command);
   TcpClientStream.Write(msg, 0, msg.Length);
   byte[] result = new byte[0];
   msg = new byte[TcpClient.ReceiveBufferSize];
   int i;
   while ((i = TcpClientStream(Read(msg, 0, msg.Length)) > 0)
   {
      Array.Resize(ref result, result.Length + i);
      Array.Copy(msg, 0, result, result.Length - i, i);
   }
   TcpClientStream.Close(); TcpClientStream = null;     // [3]
   TcpClient.Close(); TcpClient = null;                 // [4]
   return Encoding.ASCII.getString(result);
}


Результат: каждый раз, когда инициализируется TcpClient ([1]) происходит замедление примерно на секунду.
Я попытался оставить TcpClient открытым заменив это утверждение на:
if (TcpClient == null)
   TcpClient = new TcpClient(TcpAddress, TcpPort);

и комментируя [4] заявление, но [2] вызывает исключение InvalidOperationException (сокет не подключен).
Я попытался проверить, не был ли он подключен сразу после этого [1]:
if (!TcpClient.Connected)
   TcpClient.Connect(TcpAddress, TcpPort);

объект TcpClient.Connected-это false, но метод Connect вызывает исключение SocketException (сокет уже подключен)
Я также попытался оставить TcpClientStream открытым. [3] и замена [2] с:
if (TcpClientStream == null)
   TcpClientStream = TcpClient.GetStream();

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

2 Ответов

Рейтинг:
19

Rob Philpott

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

Во-первых, если строка [1] занимает секунду для выполнения, то именно столько времени требуется для выполнения поиска DNS по имени хоста и установления TCP-соединения. Кажется, что прошло много времени, но это возможно. Если это так, то вы, вероятно, захотите сохранить соединение живым для многократного использования.

Вы можете обнаружить, что присоединение StreamReader и StreamWriter к сетевому потоку облегчает жизнь - вы можете установить кодировку на конструкторах, и они позаботятся о буферизации для вас (избегая несколько отвратительного изменения размера массива). Это будет немного похоже на чтение/запись на консоль с ними. Убедитесь, что вы очистили устройство записи, когда хотите отправить данные.

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

Точно так же на приемном конце я считаю, что вы просто продолжаете читать до тех пор, пока там больше нет данных - Read возвращает <= 0. это означает, что он будет продолжать читать или блокировать там до тех пор, пока соединение не будет закрыто, так что без какого-либо разграничения вы не сможете повторно использовать соединение.

Если вы получаете небольшие задержки, стоит почитать об алгоритме Нэгла.

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


Рейтинг:
0

Menci Lucio

[1]: Нет, я думаю, что нет. Ему также нужна секунда, если я использую 127.0.0.1 в качестве адреса.

Что касается других ваших пунктов, то я следовал вашим судьбам. Но не для ASCII-кодировки. Есть больше, чем один путь, по которому я должен следовать, иногда я не получаю строку ASCII. Затем сервер записывает длину данных и остальные данные, затем клиент считывает длину данных и ждет именно этого количества байтов.

Спасибо