【问题标题】:Make Java IO Socket listen just like a ServerSocket让 Java IO Socket 像 ServerSocket 一样监听
【发布时间】:2019-09-27 11:08:20
【问题描述】:

我正在按如下方式进行财务消息传递集成:

  1. 服务器有一个接口,用于侦听来自特定 IP 和端口上的客户端套接字的请求
  2. 服务器将每个请求的响应发送回客户端套接字
  3. 另外,服务器向同一个客户端套接字发送请求

以下工作完美:

  1. 客户端socket(Java IO的Socket对象)成功向服务器接口发送请求
  2. 客户端套接字成功接收到每个请求的响应
try {
    Socket clientSocket = new Socket("example.com", 8888);    
    BufferedWriter output = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
    output.write(data);
    output.flush();
    BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    // Read responses or new request from input
} catch (IOException e) {
    e.printStackTrace();
}

客户端套接字应该接收来自服务器的任何请求 - 就像它接收来自同一服务器的响应一样。但是,当服务器向客户端套接字发起请求时,该请求永远不会被接收到。但是,我们可以在客户端环境中跟踪来自 tcpdump 的流量。

如何让客户端套接字监听来自服务器的请求,而不仅仅是响应?

更新

这可能有助于澄清有关此集成的一些内容:

一个。在这种情况下,“服务器”是第三方系统,具有集成规则

b.我的客户端套接字向服务器发送消息(上图)

c。我的实现监听来自第三方系统服务器的响应和请求,要么通过创建我自己的服务器套接字(排除),要么使用非常客户端套接字 我正在发送(我正在寻求的解决方案)

【问题讨论】:

  • 您的客户端正在侦听任何端口以获取传入请求?
  • 您需要开发一种协议,客户端可以在该协议中区分对其请求的响应和来自服务器的新请求。例如,从服务器到客户端的消息的第一个字节可能是一个字节,如果为 0,则为响应,如果非零则为请求。根据应用程序的不同,这些协议可能会变得非常复杂。
  • @RAJKUMAR 如果我的问题是对的,是的。如果绑定端口是 32111 - 由环境设置,则服务器向该端口发送请求和响应。发送端口无关紧要。
  • @JamesKPolk 已经存在,响应与新请求不同,并且有逻辑需要处理,只是为了简单起见我省略了它,但让我评论代码。
  • 我得到了答案,解决方案是创建一个单独的服务器线程,它使用与客户端套接字相同的套接字。我继续回答这个问题。

标签: java sockets io


【解决方案1】:

这是一个非常常见的错误,您在写消息时没有在末尾写“\n”(结束行标识符),因此不会读取任何消息。要解决此问题,请使用 PrintWriterprintln

这将向另一个套接字发送一条线。

这是服务器的每客户端线程模型的示例

//create a new server socket with the port as a parameter, this will bind it to the specified port: 6000
        ServerSocket server = new ServerSocket(6000);
        System.out.println("Binded");
        //create a while loop accepting sockets
        while(true)
        {
            //accept a socket
            Socket client = server.accept();
            System.out.println("Client has connected");
            //create a new thread for this socket
            new Thread(() ->
            {
                try
                {
                    /*
                    create a print writer so you can write a line, not only a message like BufferedWriter does,
                    if for some reason you still want to use BufferedWriter use
                    writer.write(message + "\n");
                     */
                    PrintWriter writer = new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
                    //Create a new reader
                    BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
                    System.out.println("Waiting for requests...");
                    //create a while loop reading requests (lines)
                    String request;
                    while((request = reader.readLine()) != null)
                    {
                        System.out.println("Received message: " + request);
                        //here find the correct response and return it, I just sent a message, replace it with the correct response
                        writer.println("Hello there! How are you today?");
                        //flush, flushing will write the data to the client
                        writer.flush();
                    }
                } catch(IOException e)
                {
                    //print an exception if it occurred, if an exception occurrs its most likely just a disconnection exception
                    e.printStackTrace();
                }
            }).start();
        }

这里是一个客户端的例子

//connect to the server at "localhost" on port 6000
        Socket client = new Socket("localhost", 6000);
        System.out.println("Connected");
        /*
        create a print writer so you can write a line, not only a message like BufferedWriter does,
        if for some reason you still want to use BufferedWriter use
        writer.write(message + "\n");
        */
        PrintWriter writer = new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
        //Create a new reader
        BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
        //write a request
        writer.println("Hi there!");
        //flush, flushing will write the data to the server
        writer.flush();
        System.out.println("Written");
        System.out.println("Waiting for responses...");
        //create a while loop reading responses (lines)
        //you may want to do this while loop in another thread
        String response;
        while((response = reader.readLine()) != null)
        {
            System.out.println("Received response: " + response);
        }

如果这涉及到财务信息,我建议使用TLS (SSL)

您不必担心 Java 已经实现并使其易于使用,这里是一个服务器示例

//create a new SSL server socket with the port as a parameter, this will bind it to the specified port: 6000
        //you create it by getting the default SSLServerSocketFactory which will create a new SSLServerSocket
        //you need to cast it since it actually returns ServerSocket but SSLServerSocket extends ServerSocket and this returns SSLServerSocket so it is safe
        SSLServerSocket server = (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket(6000);
        System.out.println("Binded");
        //set the enabled ciphersuites, until you buy a certificate set only to ciphersuites with "anon" more info on ciphersuites on https://en.wikipedia.org/wiki/Cipher_suite
        server.setEnabledCipherSuites(new String[]{"TLS_ECDH_anon_WITH_AES_256_CBC_SHA"});
        //create a while loop accepting sockets
        while(true)
        {
            //accept a socket a SSLSocket
            SSLSocket client = (SSLSocket) server.accept();
            System.out.println("Client has connected");
            //create a new thread for this socket
            new Thread(() ->
            {
                try
                {
                    //begin a handshake more info about handshakes in https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.1.0/com.ibm.mq.doc/sy10660_.htm
                    client.startHandshake();
                    /*
                    create a print writer so you can write a line, not only a message like BufferedWriter does,
                    if for some reason you still want to use BufferedWriter use
                    writer.write(message + "\n");
                     */
                    PrintWriter writer = new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
                    //Create a new reader
                    BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
                    System.out.println("Waiting for requests...");
                    //create a while loop reading requests (lines)
                    String request;
                    while((request = reader.readLine()) != null)
                    {
                        System.out.println("Received message: " + request);
                        //here find the correct response and return it, I just sent a message, replace it with the correct response
                        writer.println("Hello there! How are you today?");
                        //flush, flushing will write the data to the client
                        writer.flush();
                    }
                } catch(IOException e)
                {
                    //print an exception if it occurred, if an exception occurrs its most likely just a disconnection exception
                    e.printStackTrace();
                }
            }).start();
        }

这是一个客户端的例子

//connect to the server at "localhost" on port 6000
        //you create a SSLSocket by getting the default SSLSocketFactory which will create a new SSLSocket
        //you need to cast it since it actually returns Socket but SSLSocket extends Socket and this returns SSLSocket so it is safe
        SSLSocket client = (SSLSocket) SSLSocketFactory.getDefault().createSocket("localhost", 6000);
        System.out.println("Connected");
        //set the enabled ciphersuites to everything supported so the server can decide the ciphersuite, you can modify this to specified ciphersuites
        client.setEnabledCipherSuites(client.getSupportedCipherSuites());
        //begin a handshake more info about handshakes in https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.1.0/com.ibm.mq.doc/sy10660_.htm
        client.startHandshake();
        /*
        create a print writer so you can write a line, not only a message like BufferedWriter does,
        if for some reason you still want to use BufferedWriter use
        writer.write(message + "\n");
        */
        PrintWriter writer = new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
        //Create a new reader
        BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
        //write a request
        writer.println("Hi there!");
        //flush, flushing will write the data to the server
        writer.flush();
        System.out.println("Written");
        System.out.println("Waiting for responses...");
        //create a while loop reading responses (lines)
        //you may want to do this while loop in another thread
        String response;
        while((response = reader.readLine()) != null)
        {
            System.out.println("Received response: " + response);
        }

【讨论】:

  • 请再次阅读问题;数字 1、2、3 - 你会意识到我的客户端套接字发送到的服务器 - 第三方系统,会将响应发送回 AND 一个新请求到我的客户端套接字。所以创建一个 ServerSocket 并不适用。我唯一的愿望是你明白这一点。
  • 这里只在服务器端(主机)使用 ServerSocket,为了给您更多信息,我决定添加它,以便您更深入地了解套接字。无论如何我都需要编写代码来测试客户端代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-17
  • 2022-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-15
相关资源
最近更新 更多