Java 多线程服务器
我不认为我完全理解让多个客户端连接到一台服务器的概念。 我见过很多不同的方法,听过很多不同的方法 据我所知,每次ServerSocket从客户端套接字获得连接时,它都会创建一个新的套接字,以便继续侦听 当我看到人们用代码(服务器端)编写它时,他们总是使用一个套接字。 从那以后我一直这样做,但仍然没有取得进展 我的朋友编写了客户端,它与服务器一起工作,但是我们在让服务器全局显示消息方面遇到了问题。这就是我的结构(前3个用于服务器,最后一个用于客户端: Server.javaJava 多线程服务器,java,multithreading,sockets,data-structures,Java,Multithreading,Sockets,Data Structures,我不认为我完全理解让多个客户端连接到一台服务器的概念。 我见过很多不同的方法,听过很多不同的方法 据我所知,每次ServerSocket从客户端套接字获得连接时,它都会创建一个新的套接字,以便继续侦听 当我看到人们用代码(服务器端)编写它时,他们总是使用一个套接字。 从那以后我一直这样做,但仍然没有取得进展 我的朋友编写了客户端,它与服务器一起工作,但是我们在让服务器全局显示消息方面遇到了问题。这就是我的结构(前3个用于服务器,最后一个用于客户端: Server.java package Mai
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();
}
}
Stream.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;
}
}
Client.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(new Socket())
并接受用户类中的连接。
请让我知道让我先说一句,我已经很久没有使用Java了,但我只是用C#编写了一个简单的客户机/服务器聊天程序。希望所有的概念都是一样的 关于您的服务器类,我注意到以下几点:
至于您最初的问题,我建议如下:接受服务器端的连接,从服务器端获取为客户端创建的套接字,并将其传递给用户对象。是的,我正在阅读线程池,我将进一步研究它。对于您的#1,我从for循环返回,因此它将只创建一个用户,因为条件是ECK为null,它们都以null开头。感谢您提供的关于锁定的信息,我从来都不知道。当您说获取已创建的套接字时,您的意思是创建一个套接字实例,每次我使用serverSocket.accept()时,它将创建另一个套接字?我刚刚意识到,我想我需要放一些书签来显示从何处返回。类似于UserLoop:…编辑:我必须中断,而不是返回FacePalm是的,中断比返回更有意义!当我说“获取已创建的套接字”时,我指的是来自serverSocket.accept()的返回值.accept调用会在您的serverSocket上尝试挂起客户端连接。与serverSocket关联的原始套接字保持打开状态,准备接受更多连接。您使用返回的套接字对象与客户端通信。我仍然不能100%确定套接字。我知道serverSocket会将连接发送到新的Socket以便它可以继续侦听,但我是否需要为我获得的每个连接创建一个新的套接字实例?还是将serverSocket.accept();自动为我创建?抱歉,我迟到了几天!调用
serverSocket.accept())
将在返回时返回一个新创建的客户端套接字实例。因此,是的,它将自动为您创建对象。但是,为了让您真正与客户端进行通信,您需要在服务器类中存储一个套接字对象,以便您以后可以访问它。如果您愿意,我可以在我的回答中添加一个简短的示例,以便请确保我们意见一致。
User(new Socket())