这是一个简单的控制台应用程序,由服务器端和客户端组成。服务器端侦听某个端口,当客户端连接服务器时开始以类似菜单的方式发送问题。例如:
- 打印存在的数据
- 添加新数据
- 编辑现有数据
- 删除现有数据
醇>
客户端轮流发送菜单号并等待服务器的反应。每个命令服务器必须再次发送菜单列表。
正如您将从下面的示例中看到的那样,客户端连接到服务器并读取其菜单,然后开始与之交互。但这种互动并不像预期的那样顺利。有时数据是按件发送的。每个客户端响应后应按Enter键两次,以便从服务器获得响应。
这里准备编译我在我的应用程序中运行的问题的示例:
服务器(一个Java项目):
public class TestServer {
private static List<String> example;
static {
example = new ArrayList<String>();
for(int i = 0; i < 5; ++i) {
example.add("Data#" + i);
}
}
private static DataInputStream in;
private static DataOutputStream out;
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(30000);
System.out.println("*** Waiting for a client...");
Socket socket = serverSocket.accept();
System.out.println("*** Client connected!\n");
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
while (true) {
showUserMenu();
String clientMessage = in.readUTF();
System.out.println("Client made a choice: " + clientMessage);
try {
int answerChoice = Integer.parseInt(clientMessage);
analyzeSelection(answerChoice);
System.out.println("Waiting for client menu choice...\n");
} catch (NumberFormatException e) {
System.out.println(e.getMessage());
}
}
}
private static void analyzeSelection(int answerChoice) {
try {
switch(answerChoice) {
case 1:
printExistData();
break;
case 2:
//2. Add data
createNewData();
out.writeUTF("New data added!");
out.flush();
break;
default:
out.writeUTF("There is no such menu item. Please enter correct menu number");
out.flush();
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void createNewData() throws IOException {
StringBuilder builder = new StringBuilder();
out.writeUTF("Do you want to set change name? (y/n)");
out.flush();
if(isYes()) {
out.writeUTF("Enter data name: ");
out.flush();
builder.append(in.readUTF());
}
out.writeUTF("Do you want to set data value? (y/n)");
if(isYes()) {
out.writeUTF("Enter data value: ");
out.flush();
builder.append(in.readUTF());
}
example.add(builder.toString());
}
private static boolean isYes() throws IOException {
return in.readUTF().toLowerCase().equals("y");
}
private static void printExistData() throws IOException {
StringBuilder builder = new StringBuilder();
for(String s : example) {
builder.append("- ").append(s).append("\n");
}
out.writeUTF(builder.toString());
out.flush();
}
private static void showUserMenu() throws IOException {
StringBuilder builder = new StringBuilder();
builder.append("1. Print exist data\n").append("2. Add new data\n")
.append("*** Type menu number and press Enter.");
out.writeUTF(builder.toString());
out.flush();
}
}
客户端(另一个Java项目):
public class TestClient {
public static void main(String[] args) throws IOException {
InetAddress ipAddress = InetAddress.getByName("127.0.0.1");
System.out.println("*** Ready to connect to 127.0.0.1:30000");
Socket socket = new Socket(ipAddress, 30000);
System.out.println("*** Connection established!");
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
//Read client input from keyboard
BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
while(true) {
String serverResponse = in.readUTF();
System.out.println(serverResponse);
String clientResponse = keyboard.readLine();
out.writeUTF(clientResponse);
out.flush();
}
}
}
这是客户端和服务器之间通信的总体输出:
[SERVER]*** Waiting for a client...
[CLIENT]*** Ready to connect to 127.0.0.1:30000
[CLIENT]*** Connection established!
[SERVER]*** Client connected!
[CLIENT]1. Print exist data
2. Add new data
*** Type menu number and press Enter.
[CLIENT]1
[SERVER]Client made a choice: 1
[CLIENT]- Data#0
- Data#1
- Data#2
- Data#3
- Data#4
[SERVER]Waiting for client menu choice...
[CLIENT] //Press Enter because no menu was printed
[SERVER]Client made a choice:
[SERVER]For input string: "" //NumberFormatException (NFE)
[CLIENT]1. Print exist data
2. Add new data
*** Type menu number and press Enter.
[CLIENT]2
[SERVER]Client made a choice: 2
[CLIENT]1. Print exist data
2. Add new data
*** Type menu number and press Enter.
[CLIENT]2
[CLIENT]Do you want to set change name? (y/n)
[CLIENT]y
[CLIENT]Do you want to set data value? (y/n)
[CLIENT]y
[CLIENT]Enter data value:
[SERVER]Waiting for client menu choice...
[CLIENT]123
[SERVER]Client made a choice: 123
[SERVER]Waiting for client menu choice...
[CLIENT]New data added!
[CLIENT] //Press Enter because no menu was printed
[SERVER]Client made a choice:
[SERVER]For input string: "" //NFE
...
我发现存在某种同步问题。但我无法理解为什么会这样。
此通讯架构有什么问题?使客户端 - 服务器通信更通用的常用方法是什么?
答案 0 :(得分:0)
您的流不应该是静态的,它们甚至不应该是服务器类的成员。它们应该是Runnable
类的非静态成员,您应该在创建应创建的新线程时对其进行实例化以处理每个连接。