簡體   English   中英

Golang TCP客戶端不會向Java TCP Server發送“流結束”

[英]Golang TCP Client Does Not Send `End of Stream` to Java TCP Server

我正在編寫一個與Java TCP Server通訊的簡單Golang TCP Client。

我已成功獲取Golang客戶端,以將消息發送到Java服務器。

但是,我的Java代碼期望End of StreaminputStream.read()返回-1 )知道是時候停止讀取Client消息了。

除非我先Close() connection.Write()否則Golang似乎不會通過connection.Write()發送End of Stream消息。

以下是我的Java Server代碼:

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;
}

以下是我的Golang客戶代碼:

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

關於如何告訴Java我們已經完成了從Golang編寫消息的任何建議? 還是有更好的方法來處理Java x Golang TCP Client-Server連接?

這是一個很大的問題,因為TCP連接的基本方案之一是發送和接收:

例如

  1. 客戶端發送一條消息並等待結果。

  2. 服務器處理該消息並返回結果。

  3. 客戶對結果有所作為。

對於初學者,您可能要確保您的客戶端代碼可靠地關閉套接字。 但這不是您應該做的。

由於關閉套接字,客戶端進程應觸發TCP FIN。 由於客戶端進程干凈退出,套接字應該被關閉。 不知道為什么這不是您的情況。 你等了足夠長的時間嗎?

但是,為了避免服務器無限期掛起,您需要注意這種情況。 考慮客戶端和服務器之間存在活動TCP連接的情況。 當服務器正在等待來自客戶端的數據時,客戶端所在的位置就會斷電。 因為客戶端無法發送FIN,所以服務器連接不會有任何流量。 除非...,否則該TCP連接將永遠掛起。

您可以在服務器端設置保持活動選項或超時選項。

保持活動: https//docs.oracle.com/javase/7/docs/api/java/net/SocketOptions.html#SO_KEEPALIVE

超時: https//docs.oracle.com/javase/7/docs/api/java/net/SocketOptions.html#SO_TIMEOUT

我終於按照@nos的建議調用CloseWrite()而不是Close()來使其工作。

不得不更改我的TCP連接代碼,但它的工作原理很吸引人。

此解決方案非常適合我的目的,因為我僅打算執行1從客戶端連接發送,並且可能在關閉之前進行1讀取。

非常感謝大家的幫助!

以下是我更新的Golang客戶端代碼:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM