I'm writing a simple Golang TCP Client that talks with a Java TCP Server.
I have successfully gotten my Golang Client to send a message to my Java Server.
However, my Java code is expecting an End of Stream
(where inputStream.read()
returns -1
) to know that it's time to stop reading Client messages.
It looks like Golang does not send an End of Stream
message via connection.Write()
unless I Close()
the connection first.
Below is my Java Server code:
package com.mycompany.app;
import com.google.gson.*;
import com.google.common.primitives.Bytes;
import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.net.ServerSocket;
import java.net.SocketException;
public class MyApp {
public static void main(String[] args) {
int port = 9000;
// Start listening for messages.
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("Listening on port " + port + "...");
// Never stop listening for messages.
while (true) {
try {
// Accept a client connection.
Socket socket = serverSocket.accept();
// Read message from the client.
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
List<Byte> list = new ArrayList<Byte>();
int input = inputStream.read();
while (input != -1) {
list.add((byte) input);
input = inputStream.read();
}
byte[] jsonBytes = Bytes.toArray(list);
if (jsonBytes.length > 0) {
String jsonString = new String(jsonBytes);
System.out.println("Received: " + jsonString);
// Unmarshal from JSON.
Person person = new Gson().fromJson(jsonString, Person.class);
System.out.println("Person: " + person.Name + " " + person.Age);
}
} catch (EOFException e) {
// A client has disconnected. Do nothing.
} catch (SocketException e) {
// A client connection has been terminated unexpectedly. Do nothing.
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Person {
String Name;
int Age;
}
Below is my Golang Client code:
package main
import (
"bufio"
"encoding/json"
"fmt"
"net"
"os"
"strings"
)
type Person struct {
Name string
Age int
}
func main() {
reader := bufio.NewReader(os.Stdin)
for {
func() {
// Dial the Java Server.
conn, err := net.Dial("tcp", "localhost:9000")
if err != nil {
fmt.Println(err)
}
defer conn.Close()
fmt.Print("Enter Name: ")
strName, err := reader.ReadString('\n')
strName = strings.TrimSpace(strName)
var person Person
person.Name = strName
person.Age = 18
jsonBytes, err := json.Marshal(person)
if err != nil {
fmt.Println(err)
return
}
// Write our message to the connection.
_, err = conn.Write(jsonBytes)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("Sent: " + string(jsonBytes))
}()
}
}
Any advice on how to tell Java that we're done writing messages from Golang? Or is there a better way to handle Java x Golang TCP Client-Server connections?
This is quite a problem because one of the basic scenarios for TCP connections is Send-and-Receive:
e.g.
Client sends a message and waits for the result.
Server processes the message and returns the result.
Client does something with the result.
I finally got it to work following @nos' advice to call CloseWrite()
instead of Close()
.
Had to change my TCP Connection code a bit, but it works like a charm.
This solution is perfect for my purposes because I only plan to do 1 Send from a Client connection and possibly 1 Read before I Close it.
Many thanks to everyone who helped!
Below is my updated Golang Client code:
package main
import (
"bufio"
"encoding/json"
"fmt"
"net"
"os"
"strings"
)
// Person struct.
type Person struct {
Name string
Age int
}
func main() {
reader := bufio.NewReader(os.Stdin)
for {
func() {
// Dial the Java Server.
tcpAddr, err := net.ResolveTCPAddr("tcp", "localhost:9000")
if err != nil {
fmt.Println(err)
return
}
conn, err := net.DialTCP("tcp", nil, tcpAddr)
if err != nil {
fmt.Println(err)
return
}
defer conn.Close()
fmt.Print("Enter Name: ")
strName, err := reader.ReadString('\n')
strName = strings.TrimSpace(strName)
var person Person
person.Name = strName
person.Age = 18
jsonBytes, err := json.Marshal(person)
if err != nil {
fmt.Println(err)
return
}
// Write our message to the connection.
_, err = conn.Write(jsonBytes)
if err != nil {
fmt.Println(err)
return
}
// Tell the server that we're done writing.
err = conn.CloseWrite()
if err != nil {
fmt.Println(err)
return
}
// Read Message From Server code goes here.
fmt.Println("Sent: " + string(jsonBytes))
}()
}
}