我认为我没有完全理解让多个客户端连接到一台服务器的概念。我见过它以很多不同的方式完成,听过它是如何以很多不同的方式工作的……
据我了解,每次 ServerSocket 从客户端套接字获得连接时,它都会创建一个新的 Socket 以便它可以继续侦听。
当我看到人们用代码(服务器端)编写它时,他们总是使用一个套接字。从那以后我一直这样做,但仍然没有取得进展。
我的朋友编写了客户端,它与服务器一起工作,但我们在让服务器全局显示消息时遇到了问题。这就是我的结构(前 3 个用于服务器,最后一个用于客户端:
服务器.java
package Main;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import Streams.Stream;
public class Server {
public static final int maxConnections = 10;
ServerSocket serverSocket;
Socket socket;
User[] users = new User[maxConnections];
public Server() {
try {
serverSocket = new ServerSocket(43594);
while(Stream.streams < maxConnections) {
socket = serverSocket.accept();
for(User user : users) {
if(user == null) {
user = new User(socket);
Thread t = new Thread(user);
t.start();
System.out.println("Someone has joined the chat!");
return;
}
}
}
}catch(IOException e) { e.printStackTrace(); }
}
public static void main(String[] args) {
new Server();
}
}
用户.java
package Main;
import java.io.IOException;
import java.net.Socket;
import Streams.Stream;
public class User implements Runnable {
Stream stream;
public User(Socket socket) {
stream = new Stream(socket);
}
public void run() {
String textInput, textOutput;
while(stream.exists()) {
try{
textInput = (String) stream.recieveData();
}catch(IOException e) {
e.printStackTrace();
}catch(ClassNotFoundException e) { e.printStackTrace(); }
}
}
public void sendMessage(String message) throws IOException {
stream.sendData(message);
}
}
流.java
package Streams;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
public class Stream {
public static int streams = 0;
Socket socket;
ObjectInputStream input; ObjectOutputStream output;
Object data;
public Stream(Socket userSocket) {
streams++;
socket = userSocket;
try{
input = new ObjectInputStream(userSocket.getInputStream());
output = new ObjectOutputStream(userSocket.getOutputStream());
}catch(IOException e) { e.printStackTrace(); }
}
public void sendData(Object data) throws IOException {
output.writeObject(data);
output.flush();
}
public Object recieveData() throws IOException, ClassNotFoundException {
return data = input.readObject();
}
public boolean exists() {
if(socket.isClosed()) return false; else return true;
}
}
客户端.java
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Client extends JFrame {
private JTextField userText;
private JTextArea chatWindow;
private ObjectOutputStream out;
private ObjectInputStream in;
private String message = "";
private String serverIP;
private Socket clientSocket;
private int port = 43594;
Boolean CNC = false;
//constructor
public Client(String serverIP) {
super("Client Chat");
this.serverIP = serverIP;
userText = new JTextField();
userText.setEditable(false);
userText.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
if(userText.getText().length() > 0) {
sendMessageToServer(userText.getText());
userText.setText("");
}
}
}
);
add(new ClientMenu(), BorderLayout.NORTH);
add(userText, BorderLayout.SOUTH);
chatWindow = new JTextArea();
chatWindow.setEditable(false);
add(new JScrollPane(chatWindow), BorderLayout.CENTER);
add(new JScrollPane(new ClientTable()), BorderLayout.EAST);
setSize(600, 300);
setVisible(true);
}
//connect to server
public void startRunning() {
try{
connectToServer();
setupStreams();
whileChatting();
} catch(EOFException eofException) {
showMessage("\n Client terminated the connetion");
}catch(IOException ioException) {
ioException.printStackTrace();
}finally{
closeCrap();
}
}
//connect to server
private void connectToServer() {
showMessage("Attempting to connect to server... \n");
try {
clientSocket = new Socket(serverIP, port);
} catch (UnknownHostException e) {
CNC = true;
e.printStackTrace();
} catch (IOException e) {
CNC = true;
e.printStackTrace();
}
//showMessage("Connected to:" + connection.getInetAddress().getHostName());
}
//setup streams to send and receive messages
private void setupStreams() {
try {
out = new ObjectOutputStream(clientSocket.getOutputStream());
out.flush();
in = new ObjectInputStream(clientSocket.getInputStream());
showMessage("Stream established! \n");
showMessage("Use ::setname to change your name \n");
}catch(IOException e) { e.printStackTrace(); }
}
//while chatting with server
private void whileChatting() throws IOException{
ableToType(true);
do{
try{
message = (String) in.readObject();
showMessage("\n" + message);
}catch(ClassNotFoundException classNotfoundException) {
showMessage("\n ERROR! Message cannot be read");
}
}while(!message.equals("SERVER - END"));
}
//close the streams and sockets
private void closeCrap(){
if(CNC) {
showMessage("ERROR! Could not connect to server");
} else {
showMessage("\n Ending connections...");
ableToType(false);
try{
out.close();
in.close();
clientSocket.close();
}catch(IOException ioException) {
ioException.printStackTrace();
}
}
}
private void sendMessageToServer(String message) {
try{
out.writeObject(message);
out.flush();
}catch(IOException ioException) {
chatWindow.append("\n ERROR! Could not send message!");
}
}
//change/update chatWindow
private void showMessage(final String message) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
chatWindow.append(message);
}
}
);
}
//gives user permission to enter messages into text box
private void ableToType(final boolean tof) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
userText.setEditable(tof);
}
}
);
}
public static void main(String[] args) {
Client c = new Client("thisisatestip.zapto.org");
c.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
c.setLocationRelativeTo(null);
c.startRunning();
}
}
我在想,与其将 ServerSocket 设为静态,不如调用 User 的构造函数,例如
User(new Socket())
并接受 User 类中的连接。请告诉我