我编写了一个简单的客户端/服务器即时消息程序,它具有基本功能。
目前,我可以在服务器和一个连接的客户端之间发送/接收消息。但是,后续客户端将无法连接到服务器。
我希望实现允许以下内容的功能:
成功连接2+个客户端到服务器;
多个客户端连接到服务器并成功相互通信并与服务器通信。
我想我需要为每个连接设置一个新线程,但我不确定如何解决这个问题。
请告知(参见下面的代码)。
非常感谢任何帮助。
非常感谢。
Client.java:
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Date; //timestamp functionality
import javax.swing.*;
public class Client extends JFrame { //inherits from JFrame
//1. Creating instance variables
private JTextField userText; //where user inputs text
private JTextArea chatWindow; //where messages are displayed
private String fullTimeStamp = new java.text.SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new Date());
//fullTimeStamp - MM = months; mm = minutes; HH = 24-hour cloc
private ObjectOutputStream output; //output from Client to Server
private ObjectInputStream input; //messages received from Server
private String message ="";
private String serverIP;
private Socket connection;
//2. Constructor (GUI)
public Client(String host){ //host=IP address of server
super("Mick's Instant Messenger [CLIENT]");
serverIP = host; //placed here to allow access to private String ServerIP
userText = new JTextField();
userText.setEditable(false);
userText.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent event){
sendMessage(event.getActionCommand()); //For this to work, must build sendData Method
userText.setText(""); //resets userText back to blank, after message has been sent to allow new message(s)
}
}
);
add(userText, BorderLayout.SOUTH);
chatWindow = new JTextArea();
add(new JScrollPane(chatWindow), BorderLayout.CENTER); //allows you to scroll up and down when text outgrows chatWindow
chatWindow.setLineWrap(true); //wraps lines when they outgrow the panel width
chatWindow.setWrapStyleWord(true); //ensures that above line wrap occurs at word end
setSize(400,320);
this.setLocationRelativeTo(null); //places frame in center of screen
setVisible(true);
}
//3. startRunning method
public void startRunning(){
try{
connectToServer(); //unlike Server, no need to wait for connections. This connects to one specific Server.
setupStreams();
whileChatting();
}catch(EOFException eofException){
//Display timestamp for disconnection
showMessage("\n\n" + fullTimeStamp);
showMessage("\nConnection terminated by CLIENT! ");
}catch(IOException ioException){
ioException.printStackTrace();
}finally{
closeCrap();
}
}
//4. Connect to Server
void connectToServer() throws IOException{
showMessage(" \n Attempting connection to SERVER... \n");
connection = new Socket(InetAddress.getByName(serverIP), 6789);//Server IP can be added later
showMessage(" Connected to: " +connection.getInetAddress().getHostName() ); //displays IP Address of Server
}
//5. Setup streams to send and receive messages
private void setupStreams() throws IOException{
output = new ObjectOutputStream(connection.getOutputStream());
output.flush();
input = new ObjectInputStream(connection.getInputStream());
showMessage("\n Streams are now setup! \n");
}
//6. While chatting method
private void whileChatting() throws IOException{
//Display timestamp for connection
showMessage("\n" + fullTimeStamp);
ableToType(true);
String timeStamp = new java.text.SimpleDateFormat("HH:mm:ss").format(new Date());//timestamp
do{
try{
message = (String) input.readObject(); //read input, treat as String, store in message variable
showMessage("\n" + message);
}catch(ClassNotFoundException classNotfoundException){
showMessage("\n I don't know that object type");
}
//***broken by timestamp?***
}while(!message.equalsIgnoreCase("SERVER " + "[" + timeStamp + "]" + ": " + "END")); //Conversation happens until Server inputs 'End'
}
//7. Close the streams and sockets
private void closeCrap(){
showMessage("\n\nClosing streams and sockets...");
ableToType(false);//disable typing feature when closing streams and sockets
try{
output.close();
input.close();
connection.close();
}catch(IOException ioException){
ioException.printStackTrace(); //show error messages or exceptions
}
}
//8. Send Messages to Server
private void sendMessage(String message){
try{
String timeStamp = new java.text.SimpleDateFormat("HH:mm:ss").format(new Date());//timestamp
output.writeObject("CLIENT" + " [" + timeStamp + "]" + ": " + message);
output.flush();
showMessage("\nCLIENT" + " [" + timeStamp + "]" + ": " + message);
}catch(IOException ioexception){
chatWindow.append("\n Error: Message not sent!");
}
}
//9.change/update chatWindow
private void showMessage(final String m){
SwingUtilities.invokeLater(
new Runnable(){
public void run(){
chatWindow.setEditable(false); //disallows text editing in chatWindow
chatWindow.append(m); //appends text, which was passed in from above
}
}
);
}
//10. Lets user type
private void ableToType(final boolean tof){
SwingUtilities.invokeLater(
new Runnable(){
public void run(){
userText.setEditable(tof); //passes in 'true'
}
}
);
}
}
Server.Java:
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Date;//timestamp functionality
public class Server extends JFrame{ //inherits from JFrame
//1. Instance Variables
private JTextField userText; //where messages are typed
private JTextArea chatWindow; //where messages are displayed
private String fullTimeStamp = new java.text.SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new Date());
//fullTimeStamp - MM = months; mm = minutes; HH = 24-hour clock
//setting up the streams
private ObjectOutputStream output; //messages being sent by user
private ObjectInputStream input; //messages being received by user;
private ServerSocket server;
private Socket connection; //Socket = sets up connection between one computer and another.
//2. Constructor (GUI)
public Server(){
super("Mick's Instant Messenger [SERVER]"); //window title
userText = new JTextField();
userText.setEditable(false); //you cannot type anything, unless you are connected to someone else
userText.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent event){
sendMessage(event.getActionCommand());
userText.setText(""); //Resets editable text field after you send message
}
}
);
add(userText, BorderLayout.SOUTH);//places user text input (JTextArea) field at bottom
chatWindow = new JTextArea(15,30); //displays conversation
add(new JScrollPane(chatWindow));
chatWindow.setLineWrap(true); //wraps lines when they outgrow the panel width
chatWindow.setWrapStyleWord(true); //ensures that above line wrap occurs at word end
setSize(400,320);
this.setLocationRelativeTo(null); //places frame in center of screen
setVisible(true); //set visible on screen
}
//3.Setup and Run the Server
public void StartRunning(){
try{
server = new ServerSocket(6789, 100);
//Client connects at Port # 6789
//100 = QueueLength - the backlog of clients who can wait at port #6789 to connect to the Server
//while(true) ... means this while loop is going to run forever
while(true){
try{
waitForConnection();
setupStreams();
whileChatting(); //allows messages to pass back and forth through streams
}catch(EOFException eofException){
//connect and have conversation
//Display timestamp for disconnection
showMessage("\n\n" + fullTimeStamp);
showMessage("\nConnection terminated by SERVER! "); //displays end of stream/connection
}finally{
closeCrap();
}
}
}catch(IOException ioException){
ioException.printStackTrace(); //Displays info where there's an error!
}
}
//4. wait for connection method, then display connection info
private void waitForConnection() throws IOException{
showMessage("\n SERVER : Waiting for user(s) to connect... \n "); //tells user Server is waiting for a connection
connection = server.accept();
//socket "connection" will accept connections. Creates a socket for each new connection.
showMessage("Connected with " +connection.getInetAddress().getHostName()); //displays IP address and hostname
}
//5. setup streams method.. get streams to send and receive data
private void setupStreams() throws IOException{
output = new ObjectOutputStream(connection.getOutputStream());
//creates pathway to allow connection to whichever computer the 'connnection' socket created.
output.flush(); //clears data that gets left over in buffer when you try to connect to someone else. Flushes it over to the other person.
input = new ObjectInputStream(connection.getInputStream());
//no flush here, because you cannot flush someone else's stream
showMessage("\n Streams are now setup! \n");
}
//6. during conversation method
private void whileChatting() throws IOException{
//Display timestamp for connection
showMessage("\n" + fullTimeStamp);
String message = "You are now connected! \n ";
sendMessage(message);
ableToType(true); //will allow user to type into text box after a connection
String timeStamp = new java.text.SimpleDateFormat("HH:mm:ss").format(new Date());//timestamp
do{
try{
message = (String) input.readObject(); //read incoming message as a String and store in 'message' variable.
showMessage("\n" + message);//displays each message you receive on a new line
}catch(ClassNotFoundException classNotFoundException){
showMessage("/n I don't know what object the user has sent!");
}
//***broken by timestamp?***
}while(!message.equalsIgnoreCase("CLIENT " + "[" + timeStamp + "]" + ": " + "END")); //allows conversation until Client enters "END"
}
//7. Close Crap method - close streams and sockets after you are finished chatting
private void closeCrap(){
showMessage("\n\n Closing connections... \n");
ableToType(false);
try{
output.close(); //close your stream to other users
input.close(); //close incoming streams
connection.close(); //close the socket
}catch(IOException ioException){
ioException.printStackTrace();
}
}
//8. send message method - send message to client
private void sendMessage(String message){
try{
//writeObject method is built into Java.
String timeStamp = new java.text.SimpleDateFormat("HH:mm:ss").format(new Date());//timestamp
output.writeObject("SERVER" + " [" + timeStamp + "]" + ": " + message);
showMessage("\nSERVER" + " [" + timeStamp + "]" + ": " + message); //shows the ouput message in our conversation window
output.flush();
}catch(IOException ioException){
chatWindow.append("ERROR: Unable to send message!");
}
}
//9. updates chatWindow - instead of creating entirely new GUI each time
private void showMessage(final String text){
SwingUtilities.invokeLater(
new Runnable(){
public void run(){
chatWindow.setEditable(false); //disallows text editing in chatWindow
chatWindow.append(text); //appends text, which was passed in from above
}
}
);
}
//10. Lets user type
private void ableToType(final boolean tof){
SwingUtilities.invokeLater(
new Runnable(){
public void run(){
userText.setEditable(tof); //passes in 'true'
}
}
);
}
}
答案 0 :(得分:0)
ServerSockets在java中工作的方式是,想要连接的客户端排队等待,直到你可以ServerSocket.accept()
将第一个队列出列并返回它。因此,要将多个客户端连接到单个服务器,您需要多次调用accept。如您所知,接受也将阻止,直到客户实际可用。
您需要创建一个处理单个客户端连接的连接处理程序线程,然后在连接新客户端时关闭线程。基本上
while(true){
Socket s=server.accept();
new ConnectionHandlerThread(s).start();
// write the ConnectionHandlerThread yourself
}
我会为你写一些更详细的代码,但我在移动设备上抱歉。