Java Sockets和ServerSockets服务器/客户端GUI聊天程序
我试图学习sockets和ServerSockets在Java中是如何工作的,所以我尝试做一个聊天服务器,但同时使用线程来处理每个客户端。我想我需要对我的代码有一些新的认识,因为我不知道它为什么不起作用。程序启动,但客户端未连接且未创建。我相当肯定我的客户机类出现了问题,但我不确定需要修复什么。任何帮助,即使只是一个链接到一个有用的资源,将非常感谢。谢谢 服务器代码Java Sockets和ServerSockets服务器/客户端GUI聊天程序,java,multithreading,swing,sockets,serversocket,Java,Multithreading,Swing,Sockets,Serversocket,我试图学习sockets和ServerSockets在Java中是如何工作的,所以我尝试做一个聊天服务器,但同时使用线程来处理每个客户端。我想我需要对我的代码有一些新的认识,因为我不知道它为什么不起作用。程序启动,但客户端未连接且未创建。我相当肯定我的客户机类出现了问题,但我不确定需要修复什么。任何帮助,即使只是一个链接到一个有用的资源,将非常感谢。谢谢 服务器代码 package chatbox.server; import static java.lang.Sys
package chatbox.server;
import static java.lang.System.out;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;
public class Server {
public final static int DEFAULT_PORT = 5000;
private ServerSocket socket;
private ArrayList<Socket> clients;
public Server(int port) throws IOException {
System.out.println("Server is now online");
System.out.println("port: " + port);
this.socket = new ServerSocket(port);
System.out.println("Listening socket established");
System.out.println("Waiting for connections...");
this.clients = new ArrayList<Socket>();
while (true) {
try {
final Socket connection = this.socket.accept();
this.clients.add(connection);
Runnable incomingMsg = new Runnable() {
private InputStream inputStream = connection.getInputStream();
private InputStreamReader reader = new InputStreamReader(
inputStream);
private Scanner scanner = new Scanner(reader);
@Override
public void run() {
while (true) {
if (scanner.hasNextLine()) {
String msg = scanner.nextLine();
System.out.println("Handling message: \"" + msg
+ "\"");
notifyAllConnections(msg);
}
}
}
};
Thread thread = new Thread(incomingMsg);
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable exc) {
try {
connection.close();
} catch (IOException e1) {
e1.printStackTrace();
} finally {
clients.remove(connection);
System.out.println("Removed connection");
}
}
});
thread.start();
System.out.println("Added new connection");
} catch (IOException exc) {
System.out
.println("Error occurred.");
}
}
}
protected void notifyAllConnections(String msg) {
for (Socket sock : this.clents) {
try {
OutputStream out = sock.getOutputStream();
PrintStream printer = new PrintStream(out);
printer.println(msg);
printer.flush();
} catch (IOException exc) {
System.out.println("Message was not fully broadcast");
}
}
}
public static void main(String[] args) {
try {
Server server = new Server(
Server.DEFAULT_PORT);
} catch (IOException exc) {
System.out
.println("Could not create the server socket.");
exc.printStackTrace();
String servername = "localhost";
try {
new Client(servername, 5000);
} catch (Exception ex) {
out.println("Error" + ex.getMessage());
}
}
}
}
- 在客户端MessagesThread类的while循环中,它应该是
while(scanner.hasNextLine()){
- 在同一个类中,您将从后台线程附加到JTextArea,这是您不应该做的事情
- 在Client MessagesThread类中,实现可运行而不是扩展线程(一般建议)
- 更好的方法是使用SwingWorker,这样就可以使用publish/process更新Swing事件线程上的JTextArea
- 为了我的钱,我会先让程序在非GUI版本中运行,然后再尝试将其放入GUI
- 您的拼写错误表明代码甚至不应该编译,而clientss和clents…是什么?这是您的真实代码吗?如果我们不能复制/粘贴您的代码并进行测试,我们将很难帮助您
编辑
我已经查看并运行了您的新代码。您是否看到您正在尝试在catch块中创建一个从未调用过的新客户端 最重要的是——在运行代码时使用调试器来查看代码正在做什么或没有做什么。还可以添加println语句(更多)。如果这样做,您将看到从未调用过客户端的构造函数,并且知道在试图调用它的地方查看代码以了解原因。
- 在客户端MessagesThread类的while循环中,它应该是
while(scanner.hasNextLine()){
- 在同一个类中,您将从后台线程附加到JTextArea,这是您不应该做的事情
- 在Client MessagesThread类中,实现可运行而不是扩展线程(一般建议)
- 更好的方法是使用SwingWorker,这样就可以使用publish/process更新Swing事件线程上的JTextArea
- 为了我的钱,我会先让程序在非GUI版本中运行,然后再尝试将其放入GUI
- 您的拼写错误表明代码甚至不应该编译,而clientss和clents…是什么?这是您的真实代码吗?如果我们不能复制/粘贴您的代码并进行测试,我们将很难帮助您
编辑
我已经查看并运行了您的新代码。您是否看到您正在尝试在catch块中创建一个从未调用过的新客户端
最重要的是——在运行代码时使用调试器来查看代码正在做什么或没有做什么。如果您这样做,您将看到客户端的构造函数从未被调用,并且会知道查看您试图调用它的代码以了解原因。不确定这是否是您的问题之一,但我不知道在服务器类中进行foreach循环是否安全,因为您可以从一个线程进行迭代,并从sam中的另一个线程将内容添加到列表中e时间,对foreach循环来说可能是个问题。如果我错了,请纠正我。(或者仅仅从foreach中删除可能会损害它?)不确定这是否是您的问题之一,但我不知道在服务器类中创建foreach循环是否安全,因为您可以从一个线程进行迭代,同时从另一个线程向列表中添加内容,这可能是foreach循环的问题。如果我错了,请纠正我。(或者仅仅从foreach中删除可能会损害它?)首先,很抱歉输入错误。我一定是打字太快了。其次,我尝试了你的建议。现在,
类MessagesThread实现了Runnable
导致我将新MessagesThread.start()更改为MessagesThread.run()
但是客户端仍然没有连接到服务器。所以,你是说,一旦我移动大括号,用main方法而不是try/catch调用客户端,一切都会正常吗?@Ashton:不,我是说我看到了一个明显的粗心错误,可能永远都不应该通过你的校对。你还是我还有更多的工作要做,包括线程工作。首先,很抱歉输入错误。我一定是打字太快了。其次,我尝试了你的建议。现在,class MessagesThread实现了Runnable
导致我将new MessagesThread.start()更改为MessagesThread.run()
但是客户端仍然没有连接到服务器。所以,你是说,一旦我移动大括号,用main方法而不是try/catch调用客户端,一切都会正常吗?@Ashton:不,我是说我看到了一个明显的粗心错误,可能永远都不应该通过你的校对。你还是我还有更多的工作要做,包括穿线工作。
package chatbox.client
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import java.io.*;
import java.util.*;
import java.net.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import static java.lang.System.out;
public class Client extends JFrame {
private PrintWriter pw;
private Scanner scanner;
private JPanel chatAndSend;
private JTextArea chatWindow;
private JScrollPane mainScroll;
private JTextArea chatText;
private JScrollPane miniScroll;
private JButton send;
private Socket client;
public Client(String servername, int port) throws Exception {
this.client = new Socket(servername, port);
this.scanner = new Scanner(new InputStreamReader(
this.client.getInputStream()));
this.pw = new PrintWriter(this.client.getOutputStream());
makeGUI();
new MessagesThread().start();
}
public void makeGUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new BorderLayout());
this.chatWindow = new JTextArea(10, 20);
this.chatWindow.setEditable(false);
this.chatWindow.setLineWrap(true);
this.mainScroll = new JScrollPane(chatWindow,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
this.add(this.mainScroll, BorderLayout.NORTH);
this.chatAndSend = new JPanel();
this.chatAndSend.setLayout(new FlowLayout());
this.chatText = new JTextArea(1, 1);
this.chatText.setLineWrap(true);
this.miniScroll = new JScrollPane(chatText,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
this.chatAndSend.add(this.miniScroll);
this.send = new JButton();
this.send.setText("SEND");
this.send.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
pw.println(chatText.getText());
pw.flush();
}
});
this.chatAndSend.add(this.send);
this.add(this.chatAndSend, BorderLayout.SOUTH);
this.setVisible(true);
this.pack();
}
class MessagesThread extends Thread {
public void run() {
String line;
try {
while (true) {
line = scanner.nextLine();
chatWindow.append(line + "\n");
}
} catch (Exception exception) {
System.out.println(exception.getMessage());
}
}
}
}