java—服务器只从一个客户机线程读取输入,而忽略其余线程的输入线程客户端服务器聊天应用程序

qf9go6mv  于 2021-07-08  发布在  Java
关注(0)|答案(0)|浏览(310)

这个问题在这里已经有答案了

如何在javasocket编程中用一台服务器创建多个客户机(1个答案)
socket编程多客户端到一台服务器(5个答案)
上个月关门了。
我正在实现一个客户机-服务器聊天应用程序,其中每个客户机作为一个线程运行,两个类readthread和writethread管理多个客户机和服务器之间的通信。应用程序使用套接字连接在客户端和服务器之间读写数据。
工作原理:客户端将向服务器发送一个字符串,格式为“login:username:password“或”register:username:密码”。这个 Server 将通过套接字读取字符串,并使用所需的helper方法对其进行相应的解析。
我的问题是:当多个客户机线程尝试登录或注册时 Server 只读取来自一个客户机套接字的输入。其他客户端成功地将数据写入 Server ,但是 Server 从不读取他们发送的数据。
下面是代码的一个最小运行示例
首先,服务器类。arraylist allclients跟踪应用程序中所有注册的客户端。会议的目的 readThread 对象是读取客户端写入套接字的数据。这个 readThreadrun() 方法应该在客户端单击login、register或在服务器的套接字上写入消息时执行。

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class Server {

    private ArrayList<Client> allClients;

    public Server() throws IOException {
        this.allClients = new ArrayList<>();
    }

    public static void main(String[] args) throws IOException {

        Server server = new Server();
        int port = 1234;
        ServerSocket serverSocket = new ServerSocket(port);
        Socket socket = serverSocket.accept();

        //This is the object that I believe is causing the problem
        //The run() method in this object should be executed EVERY TIME the
        //Client clicks "Login" or "Submit" (submit register data) in the GUI
        //But what happens is that this method executes only for ONE Client...
        //The other clients successfully write to the socket, but the server never
        //reads the data that is written.
        //In short: this run() method should read data from the socket for EVERY Client
        //but it only reads data from ONE Client
        ReadThread readThread = new ReadThread(socket) {

            public void run() {
                while (true) {
                    try {
                        server.parseIncomingText(this.reader.readLine());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

            }

        };

        Thread read = new Thread(readThread);
        read.start();

    }

    public void parseIncomingText(String text){
        //Do some text processing
    }
}

接下来是 Client 班级。客户保留了一个联系人列表,他们可以从中选择与谁聊天。这个 port 使用与 Server

import gui.Login;

import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;

public class Client extends Thread {

    String name;
    String username;
    String password;
    ArrayList<Client> contacts;
    boolean isLoggedIn = false;

    public Client() {
        contacts = new ArrayList<>();
    }

    @Override
    public void run() {

        String host = "localhost";
        int port = 1234;

        Socket socket = null;
        try {
            socket = new Socket(host, port);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Login.Java is the GUI Class where the user signs
        // in or chooses to register
        new Login(socket);
    }

    //Instantiating and running three Client Threads
    public static void main(String[] args) {

        Client client1 = new Client();
        Client client2 = new Client();
        Client client3 = new Client();

        client1.start();
        client2.start();
        client3.start();
    }
}

接下来我们有两个班 ReadThread 以及 WriteThread 只需管理多个 Client s和 Server 这是 ReadThread ```
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

public class ReadThread implements Runnable {

Socket socket;
BufferedReader reader;

public ReadThread(Socket socket) {
    this.socket = socket;
    try {
        reader = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void run() {

    while (true) {
        try {

            String response = reader.readLine();
            System.out.println(response);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

}

这就是 `WriteThread` ```
import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class WriteThread implements Runnable {

    Socket socket;
    BufferedWriter writer;
    Scanner sc;

    public BufferedWriter getWriter() {
        return writer;
    }

    public WriteThread(Socket socket) {

        sc = new Scanner(System.in);
        this.socket = socket;
        try {
            writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public void run() {

        while (true) {
            String line = sc.nextLine();
            try {
                writer.write(line);
                writer.newLine();
                writer.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

最后是 Login 以及 Register gui类。这一部分对我的问题至关重要,因为这是i/o发生的地方。我会尽量减少代码。
这是你的名字 Login gui类

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.Socket;

public class Login implements ActionListener {

    Socket socketBetweenThisClientAndTheServer;
    JFrame frame;
    JPanel panel;
    JLabel labelUsername;
    JLabel labelPassword;
    JTextField textfieldUsername;
    JPasswordField passwordfieldPassword;
    JButton buttonLogin;
    JButton buttonRegister;
    String username;
    String password;

    public Login(Socket socket) {

        socketBetweenThisClientAndTheServer = socket;

        frame = new JFrame();
        frame.setSize(400, 200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        panel = new JPanel();
        panel.setLayout(null);

        labelUsername = new JLabel("Username");
        labelPassword = new JLabel("Password");
        labelUsername.setBounds(10, 20, 80, 25);
        labelPassword.setBounds(10, 50, 80, 25);

        textfieldUsername = new JTextField(32);
        passwordfieldPassword = new JPasswordField();
        textfieldUsername.setBounds(100, 20, 165, 25);
        passwordfieldPassword.setBounds(100, 50, 165, 25);

        buttonLogin = new JButton("Login");
        buttonLogin.setBounds(55, 80, 80, 25);
        buttonLogin.addActionListener(this);

        buttonRegister = new JButton("Register");
        buttonRegister.setBounds(145, 80, 120, 25);
        buttonRegister.addActionListener(this);

        panel.add(buttonRegister);
        panel.add(buttonLogin);
        panel.add(textfieldUsername);
        panel.add(passwordfieldPassword);
        panel.add(labelUsername);
        panel.add(labelPassword);

        frame.add(panel);
        frame.setVisible(true);

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == buttonLogin) {

            this.username = textfieldUsername.getText();
            this.password = passwordfieldPassword.getText();
            String textToParse = "login:" + username + ":" + password;

            //This is the part where I write a line to the server
            //I have debugged and am certain that the message is written
            //to the Server's socket successfully
            //The issue is that the server only reads the line written by
            //by only ONE of the Clients that execute this run() method
            WriteThread writeThread = new WriteThread(socketBetweenThisClientAndTheServer) {

                public void run() {
                    try {
                        this.getWriter().write(textToParse);
                        this.getWriter().newLine();
                        this.getWriter().flush();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
            };

            Thread write = new Thread(writeThread);
            write.start();

        } else if (e.getSource() == buttonRegister) {
            new Register(socketBetweenThisClientAndTheServer);
        }
    }
}

最后是 Register gui类

import app.WriteThread;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.Socket;

public class Register implements ActionListener {

    Socket socketBetweenThisClientAndTheServer;
    JFrame frame;
    JPanel panel;
    JLabel labelUsername;
    JLabel labelPassword;
    JTextField textfieldUsername;
    JPasswordField passwordfieldPassword;
    JButton buttonSubmit;

    public Register(Socket socket) {

        socketBetweenThisClientAndTheServer = socket;

        frame = new JFrame();
        frame.setSize(400, 200);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        panel = new JPanel();
        panel.setLayout(null);

        labelUsername = new JLabel("Username");
        labelPassword = new JLabel("Password");

        labelUsername.setBounds(10, 50, 80, 25);
        labelPassword.setBounds(10, 80, 80, 25);

        textfieldUsername = new JTextField(32);
        passwordfieldPassword = new JPasswordField();
        textfieldUsername.setBounds(100, 50, 165, 25);
        passwordfieldPassword.setBounds(100, 80, 165, 25);

        buttonSubmit = new JButton("Submit");
        buttonSubmit.setBounds(165, 110, 80, 25);
        buttonSubmit.addActionListener(this);

        panel.add(labelUsername);
        panel.add(labelPassword);
        panel.add(textfieldUsername);
        panel.add(passwordfieldPassword);
        panel.add(buttonSubmit);

        frame.add(panel);
        frame.setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {

        String username = textfieldUsername.getText();
        String password = passwordfieldPassword.getText();

        //This is the String I want to send to the Server for processing
        String textToParse = "register:" + username + ":" + password;

        //Similar to the object in the Login class's actionPerfored() method.
        //The message is successfully written to the Server... but the Server
        //Only reads the message sent by ONE of the clients that have executed
        //This run() method.
        WriteThread writeThread = new WriteThread(socketBetweenThisClientAndTheServer) {

            public void run() {
                try {
                    this.getWriter().write(textToParse);
                    this.getWriter().newLine();
                    this.getWriter().flush();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        };

        Thread write = new Thread(writeThread);
        write.start();

    }

}

如何让服务器读取所有客户机线程而不是一个客户机线程发送的消息?

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题