Go中客户端和服务器之间的通信

I'm a bit confused in how to do a client to send a string to a server, both in Go. When the server run ioutil.ReadAll(conexao) everything stop.

Server

    conexao, _ := listener.Accept()

    fmt.Printf("Conexão aceita %s
", 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))

The server is blocked reading data from the client, even though the server has read the complete request from the client. The client is blocked reading data from the server. To fix this issue, the server must stop reading after the complete request is read.

One way to fix for this issue is for the client to close the write side of the socket when the client is done writing the request. This will cause the server to stop reading at the end of the message. Here's the one line change for this fix:

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))

I created a working example on the playground.

Another way to fix this issue is to add message framing to the request as in HTTP and many other protocols. Framing encodes within the message information about where the message ends. This can be a message length or a distinguished byte sequence indicating the end of the message. The server is modified to read to the end of a message and then respond to the client.

The proper way is to have a specific protocol to know what to read/write. For a more advanced protocol check how websockets work for example, https://github.com/gorilla/websocket.

An easier way is to use gob.Encoder / gob.Decoder, or if you want to go more primitive you could use binary.Write / binary.Read`

// gob example:

server:

conexao, _ := listener.Accept()

fmt.Printf("Conexão aceita %s
", 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()

client:

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))