我编写了一个客户端 - 服务器程序,其中不同的客户端和服务器使用 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 来实现?
答案 0 :(得分:0)
好问题!
因为 TCP 是一种流协议,你并不真正知道消息从哪里开始和在哪里结束,除非你指定每个连接/断开只包含一个消息,或者你指定了某种定界机制(帧协议) .实际上,从 UDP 开始可能更容易,因为数据报本身可以包含整个消息。
至于成帧协议,一个例子是 Using the NETCONF Protocol over Secure Shell 规范。您当然可以设计自己的框架。