server socket

这次在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实现我们的功能了。

clipboard.png

通过上面的图示,我们可以知道,首先需要先开启服务器,然后等待客户端的连接。

当客户端通过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();
        }

    }
}

初步实现后,运行:一片空白。什么都没有发生。

出问题了很正常,断点调试一下吧。发现问题所在:

clipboard.png

客户端执行到这一行时,停止,然后服务器端接着执行;

clipboard.png

同样的服务器端也到这行就停止了。

原因是服务器一方等着输入密码,而客户端一方等着响应结果,然后又没有开始输入密码。所以双方就这么一直等着,谁都不动了。

解决

通过上面的分析,我们只要将僵局打破就能够解决问题。所以就先输入密码,然后再获取响应结果。这样就不会出问题了。

所以服务器端的代码并不需要做什么改动,只用修改客户端程序就行了。

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();
        }

    }
}

clipboard.png

成功实现!

总结

这次的实验给我提了个醒,看似简单的东西,也永远不要轻视它。只有拿出应有的实例去解决问题,问题才是你眼中那个简单的问题。

后注:在浏览网上他人实现的时候,发现有用多线程来实现的,后面我也会对这篇文章做出更新,将多线程的升级版实现与大家分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章