#.net #tcp
#.net #tcp
Вопрос:
Я пытаюсь эмулировать клиентскую программу, которая взаимодействует с существующим сервером. Я использовал wireshark и могу видеть сообщения туда и обратно. Клиентская программа подключается и отправляет строку
9 0 0 99 3 0 CR LF
CLIENT SEND
0.001157 192.168.0.210 192.168.0.197 TCP 69 61517 → 22223 [PSH, ACK] Seq=1 Ack=1 Win=131328 Len=15
затем пустая строка просто
CR LF
0.001232 192.168.0.210 192.168.0.197 TCP 56 61517 → 22223 [FIN, PSH, ACK] Seq=16 Ack=1 Win=131328 Len=2
сервер отвечает подтверждением подтверждения и возвращаемым текстовым сообщением, за которым следует CR LF
SERVER RESPONSE
0.002383 192.168.0.197 192.168.0.210 TCP 60 22223 → 61517 [ACK] Seq=1 Ack=19 Win=525568 Len=0
0.004112 192.168.0.197 192.168.0.210 TCP 66 22223 → 61517 [PSH, ACK] Seq=1 Ack=19 Win=525568 Len=12
0.004113 192.168.0.197 192.168.0.210 TCP 60 22223 → 61517 [FIN, PSH, ACK] Seq=13 Ack=19 Win=525568 Len=2
Когда я пытаюсь эмулировать клиента — все кажется одинаковым, ЗА ИСКЛЮЧЕНИЕМ ТОГО, что я не получаю [FIN, PSH, ACK], а только [PSH, ACK], и сервер не отвечает.
В своих экспериментах я обнаружил, что если я закрываю поток после записи на сервер, я вижу на wireshark, что ответ отправлен (но теперь ссылка закрыта, поэтому я не могу ее получить)
Кто-нибудь знает, как сгенерировать [FIN, PSH, ACK], оставив соединение активным??
МОЯ ПРОЦЕДУРА ОТПРАВКИ СООБЩЕНИЙ
Public Async Sub SendMessage(ByVal msg As String) 'Handles sendButton.Click
Try
If client IsNot Nothing AndAlso client.Connected Then
Dim stream As NetworkStream = client.GetStream
Dim myBytes2() As Byte = Encoding.Default.GetBytes(msg)
Try
Await stream.WriteAsync(myBytes2, 0, myBytes2.Length)
'stream.Close()
Catch ioex As System.IO.IOException
DisplayLog("Server terminated connection")
Catch odex As ObjectDisposedException
DisplayLog("client terminated connection")
Catch er As Exception
DisplayLog("ERROR Module:{" amp; GetModuleName(er) amp; "}" amp; Information.Err().Number amp; " Mess:" amp; er.Message)
End Try
End If
Catch er As Exception
DisplayLog("ERROR Module:{" amp; GetModuleName(er) amp; "}" amp; Information.Err().Number amp; " Mess:" amp; er.Message)
End Try
End Sub
Ответ №1:
Я думаю, у вас неправильные ожидания относительно того, как работает TCP. FIN — это не конец какого-либо сообщения, а конец полного соединения. Поэтому она отправляется при закрытии потока, но не после сообщения.
TCP вообще не предоставляет никакой семантики сообщений, это всего лишь поток байтов. Если вам нужна семантика сообщений, вы не можете добавить их в TCP, отправив FIN произвольно и несколько раз в существующем соединении, но вы должны добавить эту семантику сообщений поверх TCP по потоку. Типичные подходы заключаются в том, чтобы указывать в сообщении длину или какой-либо маркер конца сообщения (например, CR LF в текстовых протоколах).
Комментарии:
1. Спасибо за ваш ответ, Штеффен, да, действительно, я не совсем понимаю TCP. Однако я написал много клиентов для TCP-серверов и не сталкивался с этим конкретным сценарием. При мониторинге соединения с помощью Wireshark единственное, что я вижу, отличается от моего клиента от существующего клиента, так это то, что после отправки строки на сервер с помощью [PSH, ACK] [FIN, PSH, ACK] отправляется с завершающей строкой CR, LF . Без этого FIN (или закрытого соединения) сервер не отправит ответ… Запутался… Пол
2. @Paul: То, что вы описываете, необычно в общении, но не невозможно: клиент выполняет одностороннее отключение соединения, т. Е. сигнализирует, что он больше не будет отправлять какие-либо данные внутри соединения, но все еще может получать данные. Для достижения этого вам необходимо использовать Shutdown с аргументом
Send
после завершения отправки.