#c# #.net #sockets #server #tcpclient
Вопрос:
Я пытаюсь отправить несколько пакетов с помощью TcpClient. этот код работает на первой итерации. но после первой итерации сервер ничего не получает(хотя цикл продолжает повторяться). код на стороне сервера работает нормально, так как я тестировал его с отправителем пакетов. Что-нибудь для отправки пакетов с помощью TcpClient?
TcpClient tcpClient = new TcpClient(localIpAddress,localPort);
tcpClient.NoDelay = true;
tcpClient.Connect(remoteIpAddress,remotePort);
Stream stream=tcpClient.GetStream();
int i = 0;
while (true)
{
i = i 1;
Console.WriteLine("Message {0} Sent",i);
stream.Write(Encoding.ASCII.GetBytes(message))));
stream.Flush();
Thread.Sleep(500);
}
Комментарии:
1. пакеты-это то, как реализуется протокол TCP, но как пользователь вы должны быть совершенно не осведомлены о них. Абстракция, которую предоставляет TCP, представляет собой бесконечный поток байтов . Если вы хотите разбить этот поток на пакеты или сообщения, вам нужно реализовать такое обрамление поверх бесконечного потока байтов (или перейти к протоколу более высокого уровня, который делает это за вас).
Ответ №1:
Вы не можете точно контролировать отправку пакетов с помощью TcpClient. На самом деле вы даже не можете сделать это с помощью TCP-сокета(). Вам нужно будет использовать необработанный сокет и структурировать свои собственные TCP-пакеты.
Стек TCP решает, когда он собирается отправить пакет, на основе параметров конфигурации сокета, количества информации в буфере, времени последнего подтверждения, размера окна, RTT и некоторых других вещей.
Вы можете обмануть его, отправив много данных, что заставит стек TCP отправлять их немедленно так быстро, как только сможет. Вы также можете установить TcpClient.NoDelay()
, но это не будет работать для нескольких последовательных записей, если у вас нет разумной задержки между записями, и даже в этом случае она не гарантируется.
Вы можете совершать низкоуровневые вызовы, чтобы определить, сколько пакетов было отправлено/recv, но вы можете повлиять на это только путем настройки параметров стека TCP, и даже в этом случае он никогда не будет детерминированным из-за того, что IP-адрес является протоколом с потерями, а пакеты TCP будут отсутствовать и их необходимо будет повторно передать.
Ваша проблема с приведенным выше кодом заключается в том, что вы устанавливаете локальную точку с помощью этой строки:
TcpClient tcpClient = new TcpClient(localIpAddress,localPort);
Порт не будет повторно использоваться до тех пор, пока сокет не пройдет TIME_WAIT
фазу, которая, в зависимости от того, как выключение сокета может занять 120 секунд.
Измените эту строку на:
TcpClient tcpClient = new TcpClient();
Или если вам необходимо установить исходный IP-адрес
TcpClient tcpClient = new TcpClient(localIpAddress,0);
Вы можете прочитать об этом TIME_WAIT
здесь и о том, почему это неотъемлемая часть протокола TCP.
В качестве примечания, stream.Flush();
или NetworkStream.Flush()
абсолютно ничего не делает. Это и есть его реализация в .Чистый источник:
/// <devdoc>
/// <para>
/// Flushes data from the stream. This is meaningless for us, so it does nothing.
/// </para>
/// </devdoc>
public override void Flush() {
}
Комментарии:
1. На самом деле я пытаюсь разработать отправителя пакетов, который использует только один порт для отправки пакетов. так что любая помощь в плане изменений кода будет признательна!!
2. Если вы хотите установить исходный порт и хотите каждый раз запускать новое соединение, вам нужно будет дождаться истечения времени ожидания старого соединения из стека TCP, прежде чем вы сможете использовать его повторно. Это по замыслу и является частью протокола TCP.
3. зачем мне ждать завершения старого соединения, когда мне просто нужно отправить несколько пакетов по одному и тому же соединению?
4. Ссылка, которую я включил выше, объясняет процесс демонтажа, задержка является частью стека TCP. Этого нельзя избежать, если вы хотите повторно использовать исходный порт до истечения времени ожидания, которое может составлять от 0 до 120 секунд, в зависимости от того, как произошло отключение сокета в сети.