Golang: разделитель данных TCP / клиент / сервер
Не уверен, как сформулировать вопрос, и действительно ли он относится только к языку go, но я пытаюсь сделать так, чтобы у вас был tcp сервер и клиент, который будет обмениваться данными между ними, в основном клиент будет передавать большие объемы данных в меньшие Чанки на сервер, сервер будет ждать, чтобы прочитать каждый чанк данных, а затем ответит кодом состояния, который будет прочитан клиентом и на основании этого он выполнит другую работу.
Я использую приведенную ниже функцию в качестве теста для чтения данных с клиента и сервера (обратите внимание, я знаю, что это не идеально, но это просто тестирование):
func createBufferFromConn(conn net.Conn) *bytes.Buffer {
buffer := &bytes.Buffer{}
doBreak := false
for {
incoming := make([]byte, BUFFER_SIZE)
conn.SetReadDeadline(time.Now().Add(time.Second * 2))
bytesRead, err := conn.Read(incoming)
conn.SetReadDeadline(time.Time{})
if err != nil {
if err == io.EOF {
fmt.Println(err)
} else if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
fmt.Println(err)
}
doBreak = true
}
if doBreak == false && bytesRead == 0 {
continue
}
if bytesRead > 0 {
buffer.Write(incoming[:bytesRead])
if bytes.HasSuffix(buffer.Bytes(), []byte("|")) {
bb := bytes.Trim(buffer.Bytes(), "|")
buffer.Reset()
buffer.Write(bb)
doBreak = true
}
}
if doBreak {
break
}
}
return buffer
}
Теперь в моем случае, если я подключаюсь через Telnet(код Go также включает в себя client()
подключиться к server()
) и я набираю что-то вроде test 12345|
достаточно справедливо, что все работает просто отлично, и буфер содержит все байты, записанные из telnet(кроме канала, который удаляется вызовом Trim()).
Если я удалю if bytes.HasSuffix(buffer.Bytes(), []byte("|")) {
заблокировать код, затем через 2 секунды я получу тайм-аут, как и ожидалось, поскольку данные за это время не получены, и сервер закрывает соединение, и если я не установил крайний срок чтения из соединения, он будет ждать вечно, чтобы прочитать данные и никогда не будет знать, когда остановиться.
Я предполагаю, что мой вопрос заключается в том, что, если я отправляю несколько кусков данных, нужно ли мне указывать собственный разделитель, чтобы я знал, когда прекратить чтение из соединения и избежать бесконечного ожидания или ожидания того, что сервер прервет соединение?
1 ответ
Я предполагаю, что мой вопрос заключается в том, что, если я отправляю несколько кусков данных, мне нужно указать собственный разделитель, чтобы я знал, когда прекратить чтение из соединения и избежать ожидания навсегда или ожидания, пока сервер не прервет соединение
Да. TCP является потоковым протоколом, и нет способа определить, где сообщения внутри протокола начинаются и останавливаются, без какого-либо их формирования.
Более распространенный метод кадрирования - отправка префикса размера, чтобы получатель знал, сколько нужно прочитать, без необходимости буферизовать результаты и сканировать разделитель. Это может быть так просто, как message_length:data....
(см. также netstring и кодирование типа длина-значение).