[英]Java Instant Messenger - Connecting multiple clients to server and oneanother
I have written a simple client/server instant messaging program, which has basic functionality. 我编写了一个简单的客户端/服务器即时消息传递程序,该程序具有基本功能。
As it currently stands, I can send/receive messages between the server and one connected client. 就目前而言,我可以在服务器和一个连接的客户端之间发送/接收消息。 However, subsequent clients will not connect to the server.
但是,后续的客户端将无法连接到服务器。
I wish to implement features which allow for the following: 我希望实现允许以下功能:
Successful connection of 2+ clients to the server; 成功将2个以上的客户端连接到服务器;
Multiple clients connecting to the Server and successfully communicating with each other and server. 多个客户端连接到服务器并成功与彼此和服务器通信。
I think I need to setup a new thread for each connection, but I'm unsure how to go about this. 我想我需要为每个连接设置一个新线程,但是我不确定该怎么做。
Please advise (see my code below). 请提出建议(请参阅下面的我的代码)。
Any help is greatly appreciated. 任何帮助是极大的赞赏。
Many thanks. 非常感谢。
Client.java: 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: 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'
}
}
);
}
}
The way ServerSockets work in java is that clients that want to connect get queued until you can ServerSocket.accept()
which dequeues the first one and returns it. ServerSockets在Java中的工作方式是使要连接的客户端排队,直到您可以将第一个服务器出队并返回它的
ServerSocket.accept()
为止。 Therefore, for multiple clients to be connected to a single server, you will need to call accept multiple times. 因此,要使多个客户端连接到单个服务器,您将需要多次调用accept。 Accept will also block until a client is actually available, as you may know.
如您所知,Accept也会阻塞,直到客户端实际可用为止。
You need to create a connection handler thread that handles a single client connection, and then spawn threads off whenever a new client is connected. 您需要创建一个用于处理单个客户端连接的连接处理程序线程,然后在连接新客户端时关闭线程。 Basically
基本上
while(true){
Socket s=server.accept();
new ConnectionHandlerThread(s).start();
// write the ConnectionHandlerThread yourself
}
I would write some more detailed code for you, but I'm on mobile sorry. 我会为您编写一些更详细的代码,但是对不起,我正在使用移动设备。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.