2014-09-27 4 views
1

Я немного смущен тем, как делать клиенту для отправки строки на сервер, как в Go. Когда сервер работает ioutil.ReadAll (conexao) все останавливается.Связь между клиентом и сервером в Go

Сервер

conexao, _ := listener.Accept() 

    fmt.Printf("Conexão aceita %s\n", conexao.RemoteAddr()) 

    frase, _ := ioutil.ReadAll(conexao) 
    fmt.Println("Frase recebida") 

    convertida := strings.ToUpper(string(frase)) 

    conexao.Write([]byte(convertida)) 

    conexao.Close() 

Client

conexao, _ := net.DialTCP("tcp", nil, enderecoTCPServidor) 

fmt.Println("Conexão Estabelecida") 

conexao.Write([]byte("Gato de Botas!")) 
fmt.Println("Frase enviada") 

maiuscula, _ := ioutil.ReadAll(conexao) 

fmt.Println("Maiuscula ",string(maiuscula)) 
+1

ReadAll читает от conexao до ошибки или EOF и возвращает данные, которые он читает. Если нет ошибки или EOF, она будет блокироваться навсегда. – siritinga

+0

Итак, как я могу решить эту проблему? –

+0

Возможно, вы захотите продолжить чтение до тех пор, пока не появится ошибка (т. Е. Клиент закрывает соединение, чтобы сигнализировать, что ему больше нечего отправлять) –

ответ

1

Сервер блокирует чтение данных с клиента, даже если сервер прочитал полный запрос от клиента. Клиент блокирует чтение данных с сервера. Чтобы устранить эту проблему, сервер должен прекратить чтение после того, как будет прочитан полный запрос.

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

conexao, _ := net.DialTCP("tcp", nil, enderecoTCPServidor) 
fmt.Println("Conexão Estabelecida") 
conexao.Write([]byte("Gato de Botas!")) 
conexao.CloseWrite() // <------- Add this line 
fmt.Println("Frase enviada") 
maiuscula, _ := ioutil.ReadAll(conexao) 
fmt.Println("Maiuscula ",string(maiuscula)) 

Я создал рабочую example on the playground.

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

1

Правильный путь должен иметь определенный протокол, чтобы знать, что для чтения/записи. Для более продвинутого протокола проверьте, как работают веб-камеры, например, https://github.com/gorilla/websocket.

Простой способ заключается в использовании gob.Encoder/gob.Decoder, или если вы хотите пойти более примитивным вы могли бы использовать binary.Write/binary.Read `

// завала пример:

сервер:

conexao, _ := listener.Accept() 

fmt.Printf("Conexão aceita %s\n", conexao.RemoteAddr()) 
enc := gob.NewEncoder(conexao) 
dec := gob.NewDecoder(conexao) 
var frase string 
if err := dec.Decode(&s); err != nil { 
    fmt.Println("error") 
} 
enc.Encode(strings.ToUpper(string(frase))) 
conexao.Close() 

клиент:

conexao, _ := net.DialTCP("tcp", nil, enderecoTCPServidor) 

fmt.Println("Conexão Estabelecida") 
enc := gob.NewEncoder(conexao) 
dec := gob.NewDecoder(conexao) 
enc.Encode("Gato de Botas!") 
var maiuscula string 
dec.Decode(&maiuscula) 
fmt.Println("Maiuscula ", string(maiuscula))