Hot questions for Using Transmission Control Protocol in go

Question:

I had a tough time trying to deploy my Java project to Google cloud engine. I read most of Google cloud documentation but I still can't figure it out.

What I want is just tcp communication. I don't need the HTML itself to do something. A lot of guides talk about servlets and http get and post but I need just tcp. Maybe I lack of information and that is why I can't manage it.

So first - do I need some sort of http sever to run just tcp requests? And if not how can I deploy my project?

Right now my project has just Java. I used IntelliJ if it matters. It is something like that.

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class MainServer {

    public static void main(String[] args) {
        final int SERVER_PORT = 3000;
        final int SERVER_TIMEOUT = 5000;

        try (ServerSocket serverSocket = new ServerSocket(SERVER_PORT)) {
            while (true) {
                try {
                    Socket clientSocket = serverSocket.accept();
                    clientSocket.setSoTimeout(SERVER_TIMEOUT);
                    new ClientThread(clientSocket).start();
                } catch (IOException ignored) {
                }
            }
        } catch (IOException ignored) {
        }
    }
}

And in ClientThread I work with every request.

I tried it locally and it works perfectly.

Now I just need to deploy this project somehow to the compute engine and make it work.

Additionally I installed Java JRE on the server. I hope port 3000 is ok if not I can change it.

Thanks in advance and sorry if I wasn't so clear.


Answer:

Create a runnable JAR file. Copy it to your Compute Engine instance. Run it.

If you want to be able to start/stop this program without logging into your instance, then you need a simple servlet. Look at the embedded Jetty - this is probably the best solution for this use case.

Question:

I'm using Java Sockets from package java.net. I read that they use TCP, so I was curious to know which ARQ (Automatic Repeat reQuest) protocol they implement by default. I've looked in the documentation but could not find any information about this.

I know there are three main ARQ algorithms: stop-and-wait, go-back-n and selective repeat. Which one do Java Sockets use?


Answer:

The Java Socket APIs are typically wrappers around the operating systems socket APIs. The java APIs do simply instruct the operating system to create/bind/close sockets and to read or write data from them. The internal behavior of the sockets depends on the operating systems implementation. Sou would need to look up what the operating system you use (Windows/Linux/MacOS/etc.) uses and whether that is configurable.

Question:

I am trying to create a TCP client (golang) server (Java) application where the client writes, the server echos this text and returns the message back to the client, which subsequently echos the reply.

Server code (Java):

public static void main(String[] args) throws Exception {

    int port = 4444;
    ServerSocket serverSocket = new ServerSocket(port);
    System.err.println("Started server on port " + port);

    while (true) {
        Socket clientSocket = serverSocket.accept();
        System.err.println("Accepted connection from client");

        BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

        PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
        String s;
        while ((s = in.readLine()) != null) {
            out.println(s);
            System.out.println(s);

        }

        System.err.println("Closing connection with client");
        out.close();
        in.close();
        clientSocket.close();
    }
}

Client code (golang):

package main

import (
    "net"
    "os"
)

func main() {
    strEcho := "Hello"
    servAddr := "localhost:4444"
    tcpAddr, err := net.ResolveTCPAddr("tcp", servAddr)
    if err != nil {
        println("ResolveTCPAddr failed:", err.Error())
        os.Exit(1)
    }

    conn, err := net.DialTCP("tcp", nil, tcpAddr)
    if err != nil {
        println("Dial failed:", err.Error())
        os.Exit(1)
    }

    _, err = conn.Write([]byte(strEcho))
    if err != nil {
        println("Write to server failed:", err.Error())
        os.Exit(1)
    }

    println("write to server = ", strEcho)

    reply := make([]byte, 1024)
    _, err = conn.Read(reply)

    if err != nil {
        println("Write to server failed:", err.Error())
        os.Exit(1)
    }

    println("reply from server=", string(reply))

    conn.Close()
}

When I start the Java server and then run the Go application, the server says that the connection has been accepted (i.e. "Accepted connection from client") but never returns the echo back to the client. The client stalls on "write to server = Hello" i.e. the write to the server works fine, but the read back to the client does not. Any idea why this is happening?


Answer:

Try sending a newline character to match the readLine statement on the server-side

strEcho := "Hello\n"

Question:

I'm writing a Java TCP Client that connects to a Golang TCP Server.

The server uses the below code to read messages from clients:

func (tcpHandler TCPHandler) getClientMsgBytes(connection *net.TCPConn) ([]byte, error) {
    clientMsgBytes, err := ioutil.ReadAll(connection)
    if err != nil {            
        return nil, err
    }       

    return clientMsgBytes, nil
}

My client uses the below code to send messages to the server:

try (Socket socket = new Socket("localhost", 9000)) {
    byte[] message = getMessage();

    DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());

    outputStream.write(commandMessage);     

    // Read message from the sever...          
}

My problem is that the server keeps waiting for the client to write its message even after all bytes of the message have been written to the stream. This seems to be because the ioutil.ReadAll function is waiting for an io.EOF error as the signal to stop reading from the stream.

How can I tell Go that I am done writing to the TCP stream from Java? I can change both the Java TCP Client and Golang TCP Server codes, if that helps.

NOTE: The server was written like that because our Go TCP Client uses the below code:

func writeToConnection(connection *net.TCPConn, tcpCommand structs.TCPCommand) error {
    messageBytes, err := json.Marshal(tcpCommand)
    if err != nil {
        err = merry.Wrap(err)
        return err
    }

    _, err = connection.Write(messageBytes)
    if err != nil {
        err = merry.Wrap(err)
        return err
    }

    err = connection.CloseWrite()
    if err != nil {
        err = merry.Wrap(err)
        return err
    }

    return nil
}

Answer:

Call shutdownOputput to match the code in the Go client.

Question:

I have a simple echo-server in Java:

 int portNumber = 4444;

    try (
        ServerSocket serverSocket =
            new ServerSocket(Integer.parseInt(args[0]));
        Socket clientSocket = serverSocket.accept();     
        PrintWriter out =
            new PrintWriter(clientSocket.getOutputStream(), true);                   
        BufferedReader in = new BufferedReader(
            new InputStreamReader(clientSocket.getInputStream()));
    ) {
        String inputLine;
        while ((inputLine = in.readLine()) != null) {
            out.println(inputLine);
            System.out.println(inputLine);
        }
    } catch (IOException e) {
        System.out.println("Exception caught when trying to listen on port "
            + portNumber + " or listening for a connection");
        System.out.println(e.getMessage());
    }

and a simple golang client:

func main() {
    fmt.Println("start client")
    conn, err := net.Dial("tcp", "localhost:4444")
    if err != nil {
        log.Fatal("Connection error", err)
    }
    conn.Write([]byte("hello world"))
    conn.Close()
    fmt.Println("done")
}

When I start the server and then run the client, the server echo's "hello world" as expected but then the server exits/terminates.

Q. How do I prevent this Java termination and force the server to continually wait for more client requests?


Answer:

When the client terminates, the readLine on server side will result in the end of the stream. So if you want the server to continuously listen for new connections the simply put the above server code in a endless loop.

e.g.

while (true) {
   // above code
}

For a play application that would be adequate.