这次在java实验的时候,要求使用server socket
编写服务器和客户端的网络通信。最开始认为应该是挺简单的,但是后来发现低估了它。出现了不少的问题,所以也在这里与大家分享。
问题描述
服务器程序的处理规则如下:
1) 向客户端程序发送Verifying Server!。
2) 若读口令次数超过3次,则发送Illegal User!给客户端,程序退出。否则向下执行步骤3)。
3) 读取客户端程序提供的口令。
4) 若口令不正确,则发送PassWord Wrong!给客户端,并转步骤2),否则向下执行步骤5)。
5) 发送Registration Successful!给客户端程序。客户端程序的处理规则如下:
1) 读取服务器反馈信息。
2) 若反馈信息不是Verifying Server!,则提示Server Wrong!,程序退出。否则向下执行步骤3)
3) 提示输入PassWord并将输入的口令发送给服务器。
4) 读取服务器反馈信息。
5) 若反馈信息是Illegal User!,则提示Illegal User!,程序退出。否则向下执行步骤6)
6) 若反馈信息是PassWord Wrong!,则提示PassWord Wrong!,并转步骤3),否则向下执行步骤。
7) 输出Registration Successful!。
初步实现
首先,我们一定要清楚,这次和之前的程序不同,虽然都是在本地上,但是服务器
和客户端
需要两个启动程序来实现,以达到我们模拟远程连接的效果。
然后就是如何利用socket
实现我们的功能了。
通过上面的图示,我们可以知道,首先需要先开启服务器
,然后等待客户端的连接。
当客户端通过socket
进行连接后,服务器端也会建立一个socket
对象来帮助实现服务器和客户端的通信。
这时候就建立了一个TCP连接
,我们就可以在服务器写数据,然后在客户端读取了,实现双方通信。
最后,当有一方决定通信结束,就会关闭连接。通信结束。
下面是初步实现的代码:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务器
*/
public class ServerTest {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(8080);
Socket clientSocket = serverSocket.accept();
String welcome = "verifying server!";
OutputStream outputStream = clientSocket.getOutputStream();
outputStream.write(welcome.getBytes());
InputStream inputStream = clientSocket.getInputStream();
int time = 0;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String password = bufferedReader.readLine();
// 获取登录信息,允许3次登录
while (time < 3) {
if (password.equals("123")) {
outputStream.flush();
outputStream.write("Registration Successful!".getBytes());
break;
} else {
outputStream.write("PassWord Wrong!".getBytes());
outputStream.flush();
password = bufferedReader.readLine();
time++;
}
}
if (time >= 3) {
outputStream.flush();
outputStream.write("Illegal User!".getBytes());
}
outputStream.close();
clientSocket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.*;
import java.net.Socket;
/**
* 客户端
*/
public class ClientTest {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1", 8080);
String aline = new String();
// 获取输入流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
aline = bufferedReader.readLine();
// 访问失败
if (!aline.equals("verifying server!")) {
System.out.println("Server Wrong!");
return;
}
// 获取响应结果
String feedback = bufferedReader.readLine();
while (feedback == null || feedback.equals("PassWord Wrong!")) {
if (feedback != null) {
if (feedback.equals("PassWord Wrong!")) {
System.out.println("PassWord Wrong!");
} else if (feedback.equals("Registration Successful!")) {
System.out.println("Registration Successful!");
break;
}
}
System.out.println("输入密码:");
// 输入密码
Scanner scanner = new Scanner(System.in);
OutputStream outputStream = socket.getOutputStream();
String password = scanner.nextLine();
outputStream.write(password.getBytes());
feedback = bufferedReader.readLine();
}
// 关闭连接
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
初步实现后,运行:一片空白
。什么都没有发生。
出问题了很正常,断点调试一下吧。发现问题所在:
客户端执行到这一行时,停止,然后服务器端接着执行;
同样的服务器端也到这行就停止了。
原因是服务器一方等着输入密码,而客户端一方等着响应结果,然后又没有开始输入密码。所以双方就这么一直等着,谁都不动了。
解决
通过上面的分析,我们只要将僵局打破就能够解决问题。所以就先输入密码
,然后再获取响应结果
。这样就不会出问题了。
所以服务器端的代码并不需要做什么改动,只用修改客户端程序就行了。
import java.io.*;
import java.net.Socket;
/**
* 客户端
*/
public class ClientTest {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1", 8080);
String aline = new String();
// 获取输入流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
aline = bufferedReader.readLine();
// 访问失败
if (!aline.equals("verifying server!")) {
System.out.println("Server Wrong!");
return;
}
// 主要修改这里,不先获取响应结果
// 初始化响应结果
String feedback = null;
while (true) {
if (feedback != null) {
if (feedback.equals("PassWord Wrong!")) {
System.out.println("PassWord Wrong!");
} else if (feedback.equals("Registration Successful!")) {
System.out.println("Registration Successful!");
break;
}
}
System.out.println("输入密码:");
// 输入密码
Scanner scanner = new Scanner(System.in);
OutputStream outputStream = socket.getOutputStream();
String password = scanner.nextLine();
outputStream.write(password.getBytes());
feedback = bufferedReader.readLine();
}
// 关闭连接
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
成功实现!
总结
这次的实验给我提了个醒,看似简单的东西,也永远不要轻视它。只有拿出应有的实例去解决问题,问题才是你眼中那个简单的问题。
后注:在浏览网上他人实现的时候,发现有用多线程来实现的,后面我也会对这篇文章做出更新,将多线程的升级版实现与大家分享。