通过 XML(Java、TCP)进行客户端-服务器通信

时间:2021-05-06 18:41:55

标签: java xml sockets tcp

我编写了一个客户端 - 服务器程序,其中不同的客户端和服务器使用 xml 和 tcp 套接字通过请求/回复进行通信。后来我想添加udp套接字。这是当前代码:

客户:

package network.client;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

public class Client implements Closeable {
    private Socket socket;

    public Client(String host, int port) throws IOException {
        this(new Socket(host, port));
    }

    public Client(Socket s) {
        this.socket = s;
    }

    @Override
    public void close() throws IOException {
        this.socket.close();
    }

    public void send(String msg) throws IOException {

        OutputStream out=this.socket.getOutputStream();
        out.write(msg.getBytes());
        out.flush();
        socket.shutdownOutput();

    }

    public void recv() {
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            String request="";
            String temp=in.readLine();
            while(temp!=null) {
               request+=temp;
               temp=in.readLine();
            }
            socket.shutdownInput();
            
            System.out.println("Client: " + request);
            System.out.println(request.toString().length());
        } catch (IOException ex) {
            System.err.println("Error: Unable to read server response\n\t" + ex);
        }        
    }

    public static void main(String[] args) {
        // Make sure command line arguments are valid
        String ip="127.0.0.1";
        int port=5000;

        StringBuilder sb = new StringBuilder();
       
        sb.append("stuff");
        System.out.println(sb.toString().length());
        try (Client c = new Client(ip, port)) {
            c.send(sb.toString());
            c.recv();
            c.close();
            
        } catch (IOException ex) {
            System.err.println("Error: " + ex);
        }
    }
}

服务器:

package network.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server {

    private static ServerSocket serversocket;
    private static ExecutorService threadpool;
    private String ip;
    private int port;

    public static void main(final String[] args) {

        Server2 server;
        String ip = "127.0.0.1";
        int port = 5000;

        try {
            server = new Server(ip, port);
            
            while (true) {
                Runnable requestHandler = null;
                try {
                    requestHandler = new TCPRequestHandler(serversocket.accept());

                } catch (IOException io) {
                    System.out.println("Accepting client connection failed");
                    io.printStackTrace();
                }
                threadpool.submit(requestHandler);
            }
            
        } catch (IOException io) {
            System.out.println(io.getMessage());
            io.printStackTrace();
        }
        System.out.println("end");

    }

    public Server(String ip, int port) throws IOException {
        this.ip = ip;
        this.port = port;
        try {
            this.serversocket = new ServerSocket();
            serversocket.bind(new InetSocketAddress(ip, port));
        } catch (IOException io) {
            throw new IOException("Creating the ServerSocket failed");
        }
        
        System.out.println("Binding the server succeeded");

        this.threadpool = Executors.newCachedThreadPool();
    }
}

请求处理器:

public class TCPRequestHandler extends Thread{
    private Socket clientSocket=null;
    
    public TCPRequestHandler(Socket clientSocket) {
        this.clientSocket=clientSocket;
    }       
    
    public void run(){
        System.out.println("Accepted client connection (" + clientSocket.getInetAddress().getHostAddress() + ", " + clientSocket.getPort() + ")");
        byte[] buffer = new byte[1024];
        int count;
            try {
                BufferedReader in =new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                OutputStream out = clientSocket.getOutputStream();
                
                String request="";
                String temp=in.readLine();
                while(temp!=null) {
                   request+=temp;
                   temp=in.readLine();
                }
                System.out.println("Server:" + request);
                System.out.println(request.toString().length());
                // do stuff with xml request
               
                out.write(request.getBytes());
                out.flush();
                
                clientSocket.shutdownInput();
                clientSocket.shutdownOutput();
            } catch (IOException io) {
                System.err.println("IO initialization failed");
            }
    }
}

XML 请求:

<Request>
  <Info Attribute1="" Attribute2=""></Info>
  <Info Attribute1="" Attribute2=""></Info>
</Request>

XML Reply(客户端需要发送回属性的开销,所以我必须发送两次):

<Reply>
  <Info Attribute1="" Attribute2="">GoodReply</Info>
  <Info Attribute1="" Attribute2="">GoodReply</Info>
</Reply>

我的问题有两层:

1.) 也许我在客户端 - 服务器编程中做了一些不寻常的事情(忘记关闭某些东西,不寻常的流读取/处理)。读取客户端/服务器消息的每一行似乎是例如对我来说很奇怪,因为我宁愿阅读 xml 消息,直到它独立于其行完成)。随时为我提供“良好的编码风格”建议:-)

2.) 目前我将通过 StringBuilder 组装 XML 并仅发送整个字符串的字节,而没有像 \r \n 这样的特殊字符。我不确定如何使用像 Stax 这样的通用 api 来做到这一点(这似乎很复杂)。应用程序需要解析属性及其内容。有没有更简单/更常见的方法来解决这个问题? 如果不是:如何使用例如 Stax 来实现?

1 个答案:

答案 0 :(得分:0)

好问题!

因为 TCP 是一种流协议,你并不真正知道消息从哪里开始和在哪里结束,除非你指定每个连接/断开只包含一个消息,或者你指定了某种定界机制(帧协议) .实际上,从 UDP 开始可能更容易,因为数据报本身可以包含整个消息。

至于成帧协议,一个例子是 Using the NETCONF Protocol over Secure Shell 规范。您当然可以设计自己的框架。