Stuck with Multi-Client Chat Application - java

I'm trying to make a MultiClient Chat Application in which the chat is implemented in the client window. I've tried server and client code for the same. I've got two problems:
A. I believe the code should work but, server to client connections are just fine but information isn't transferred between clients.
B. I need a way to implement private one-to-one chat in case of more than two clients, I've used a class to store the information of the Socket object returned for each connection being established, but I can't figure out how to implement it.
The server code is:
import java.io.*;
import java.net.*;
class ClientInfo {
Socket socket;
String name;
public ClientInfo(Socket socket, String name) {
this.socket = socket;
this.name = name;
}
}
public class server {
private ObjectInputStream input[] = null;
private ObjectOutputStream output[] = null;
private String value = null;
private static ServerSocket server;
private Socket connection = null;
private static int i = -1;
public static void main(String args[]) {
try {
server = new ServerSocket(1500, 100);
while (true) {
System.out.println("Waiting for connection from client");
Socket connection = server.accept();
i++;
System.out.println("Connection received from " + (i + 1) + " source(s)");
//System.out.println(i);
new ClientInfo(connection, "Client no:" + (i + 1));
innerChat inc = new server().new innerChat(connection);
}
} catch (Exception e) {
System.out.println("Error in public static void main! >>>" + e);
}
}// end of main!!!
class innerChat implements Runnable {
private Socket connection = null;
public innerChat(Socket connection) {
this.connection = connection;
Thread t;
t = new Thread(this);
t.start();
}
public void run() {
try {
output[i] = new ObjectOutputStream(connection.getOutputStream());
output[i].flush();
input[i] = new ObjectInputStream(connection.getInputStream());
} catch (Exception e) {
}
}
}
}
And the client code is
import java.net.*;
import java.io.*;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.*;
import java.awt.event.*;
public class ChatappClient {
private static int port = 1500;
JFrame window = new JFrame("Chat");
JButton sendBox = new JButton("Send");
JTextField inputMsg = new JTextField(35);
JTextArea outputMsg = new JTextArea(10, 35);
private ObjectInputStream input;
private ObjectOutputStream output;
public static void main(String[] args) throws Exception {
ChatappClient c = new ChatappClient();
c.window.setVisible(true);
c.window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
c.run();
}
public ChatappClient() {
inputMsg.setSize(40, 20);
sendBox.setSize(5, 10);
outputMsg.setSize(35, 50);
inputMsg.setEditable(true);
outputMsg.setEditable(false);
window.getContentPane().add(inputMsg, "South");
window.getContentPane().add(outputMsg, "East");
window.getContentPane().add(sendBox, "West");
window.pack();
sendBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
output.writeObject(inputMsg.getText());
outputMsg.append("\n" + "Client>>>" + inputMsg.getText());
output.flush();
} catch (IOException ie) {
outputMsg.append("Error encountered! " + ie);
}
inputMsg.setText("");
}
});
inputMsg.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
output.writeObject(inputMsg.getText());
outputMsg.append("\n" + "Client>>>" + inputMsg.getText());
output.flush();
} catch (IOException ie) {
outputMsg.append("Error encountered! " + ie);
}
inputMsg.setText("");
}
});
}
private void run() throws IOException {
Socket clientSocket = new Socket("127.0.0.1", port);
output = new ObjectOutputStream(clientSocket.getOutputStream());
output.flush();
input = new ObjectInputStream(clientSocket.getInputStream());
outputMsg.append("I/O Success");
String value = null;
while (true) {
try {
value = (String) input.readObject();
} catch (Exception e) {
}
outputMsg.append(value + "\n");
}
}
}

Your code looks like it could be improved quite a bit. Your main method for instance should have none of that code in it. It should start your Server class, and that's it (and note that class names should begin with an upper case letter as per Java standards which I strongly advise you to follow).
I'm trying to make a MultiClient Chat Application in which a Server does nothing but listen and create connections.
The Server is going to have to do more than that. It will need to create Clients, it will need to maintain a collection such as an ArrayList of Clients such as an ArrayList<ChatappClient> Otherwise how do you expect the Server to connect two Clients together?
I think that in all you're going to need to think the structure and connections of this program out in more depth before starting to write code.

Related

Chat Program: Client to Server Connectivity Issue

Project Summary
Goal: A simple application that connects a client to a server hosted on one computer and allows that client from another computer to send chat messages to everyone on that specified server.
Class ClientWindow: Runs an application that prompts the user to enter in a server ID and port. Once entered, it starts the chat program.
Problem:
For some reason unknown to me, the chat program ONLY works when connecting to a server that you've created on your own computer. Other clients from other computers cannot connect to that server.
Possible reasons for problem:
I might have incorrectly constructed the server's receiving/sending sockets
I might have incorrectly constructed the client's receiving/sending sockets
Something is getting wonky in the packets being sent between client and server
Somehow IP addresses for the sockets are being defined incorrectly
Here is the code for the chat program.
Start server
This class starts the server on the specified port. (12348 in this instance)
package server;
public class ChatServer {
public static void main(String[] args) {
// TODO Auto-generated method stub
Server.start(12348);
}
}
Server
This is the class that creates the server and listens for client connections and messages.
package server;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.ArrayList;
public class Server {
private static DatagramSocket socket;
private static boolean running;
private static int ClientID; // Ensures that no two users have the same client ID
private static ArrayList<ClientInfo> clients = new ArrayList<ClientInfo>();
public static void start(int port) {
try {
socket = new DatagramSocket(port);
System.out.println("Application Starting...");
running = true;
listen();
System.out.println("Server started on port: " + port);
} catch (Exception e) {
System.out.println("Failed somewhere");
e.printStackTrace();
}
}
private static void broadcast(String message) {
for (ClientInfo info : clients) {
send(message, info.getAddress(), info.getPort());
}
}
private static void send(String message, InetAddress address, int port) {
try {
message += "\\e";
byte[] data = message.getBytes();
DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
socket.send(packet);
System.out.println("Sent message to," + address.getHostAddress() + ":" + port);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void listen() {
Thread listenThread = new Thread("ChatProgram Listener Thread") {
public void run() {
try {
while(running) {
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length);
socket.receive(packet);
String message = new String(data);
//Identify where the end of the message is
message = message.substring(0, message.indexOf("\\e"));
//Manage message
if(!isCommand(message, packet)) {
broadcast(message);
}
}
} catch(Exception e){
e.printStackTrace();
}
}
}; listenThread.start();
}
/*
* SERVER COMMAND LIST
* \con:[name] -> Connects client to server
* \dis:[id] -> Disconnects client from server
*
*
*
*/
private static boolean isCommand(String message, DatagramPacket packet) {
if (message.startsWith("\\con:")) {
// RUN CONNECTION CODE
String name = message.substring(message.indexOf(":") + 1);
clients.add(new ClientInfo(name, ClientID++, packet.getAddress(), packet.getPort()));
broadcast("User " + name + " Connected!");
return true;
}
if (message.startsWith("\\dis:")) {
// RUN DISCONNECTION CODE
return true;
}
return false;
}
public static void stop() {
running = false;
}
}
Start Client
Starts the client application.
package client;
import java.awt.EventQueue;
import java.awt.Frame;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextField;
import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.awt.event.ActionEvent;
public class ClientWindow {
private JFrame frmChatProgram;
private JTextField textField;
private static JTextArea textArea = new JTextArea();
private Client client;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
ClientWindow window = new ClientWindow();
window.frmChatProgram.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public ClientWindow() throws UnknownHostException {
initialize();
String name = JOptionPane.showInputDialog("Enter name:");
String servIp = JOptionPane.showInputDialog("Enter server IP address:");
String port = JOptionPane.showInputDialog("Enter server port:");
int parsedPort = Integer.parseInt(port);
//InetAddress inetAddress = InetAddress.getLocalHost();
client = new Client(name, servIp, parsedPort);
}
private void initialize() {
frmChatProgram = new JFrame();
frmChatProgram.setResizable(false);
frmChatProgram.setTitle("Chat Program");
frmChatProgram.setBounds(100, 100, 620, 446);
frmChatProgram.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmChatProgram.setBackground(Color.WHITE);
frmChatProgram.getContentPane().setBackground(Color.DARK_GRAY);
frmChatProgram.getContentPane().setLayout(new BorderLayout(0, 0));
textArea.setForeground(Color.WHITE);
textArea.setBackground(Color.DARK_GRAY);
JScrollPane scrollPane = new JScrollPane(textArea);
frmChatProgram.getContentPane().add(scrollPane, BorderLayout.CENTER);
JPanel panel = new JPanel();
panel.setBackground(Color.GRAY);
frmChatProgram.getContentPane().add(panel, BorderLayout.SOUTH);
panel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
textField = new JTextField();
textField.setBackground(Color.WHITE);
panel.add(textField);
textField.setColumns(40);
JButton btnNewButton = new JButton("Send");
btnNewButton.addActionListener(e ->{
if (!textField.getText().equals("")) {
client.send(textField.getText());
textField.setText("");
}
});
panel.add(btnNewButton);
frmChatProgram.setLocationRelativeTo(null);
}
public static void printToConsole(String message) {
textArea.setText(textArea.getText() + message + "\n");
}
}
Client
Creates a client connection and listener for that client
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import server.ClientInfo;
public class Client {
private DatagramSocket socket;
private InetAddress address;
private int port;
private boolean running;
private String name;
public Client(String name, String address, int port) {
try {
this.name = name;
this.address = InetAddress.getByName(address);
this.port = port;
socket = new DatagramSocket();
socket.connect(this.address, port);
running = true;
listen();
send("\\con:" + name);
} catch (Exception e) {
e.printStackTrace();
}
}
public void send(String message) {
try {
if (!message.startsWith("\\")) {
message = name+": "+message;
}
message += "\\e";
byte[] data = message.getBytes();
DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
socket.send(packet);
System.out.println("Sent message to," + address.getHostAddress() + ":" + port);
} catch (Exception e) {
e.printStackTrace();
}
}
private void listen() {
Thread listenThread = new Thread("ChatProgram Listener Thread") {
public void run() {
try {
while (running) {
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length);
socket.receive(packet);
String message = new String(data);
// Identify where the end of the message is
message = message.substring(0, message.indexOf("\\e"));
// Manage message
if (!isCommand(message, packet)) {
ClientWindow.printToConsole(message);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}; listenThread.start();
}
private static boolean isCommand(String message, DatagramPacket packet) {
if (message.startsWith("\\con:")) {
// RUN CONNECTION CODE
return true;
}
if (message.startsWith("\\dis:")) {
// RUN DISCONNECTION CODE
return true;
}
return false;
}
}
I assume that you are asking about the possible reasons that your code is not be working:
1) I might have incorrectly constructed the server's receiving/sending sockets.
That is possible. You should be able to tell that by using a debugger to examine the packets on the server side.
2) I might have incorrectly constructed the client's receiving/sending sockets
Ditto ...
3) Something is getting wonky in the packets being sent between client and server
This is the most likely:
It could be a packet-level routing problem ... though that is likely to have broader effects.
It could be firewall issue
It could be an MTU issue
It could even be a broken switch, etc.
4) Somehow IP addresses for the sockets are being defined incorrectly
That is possible.
There are various things you could do to diagnose / eliminate the various possibilities. But this is not really a StackOverflow problem.

How to handle multiple streams from a lobby server to clients

So, I'm having an issue with a project of mine. I'm writing a multiplayer lobby system which will enable multiple users to join a lobby, readying themselves by pressing a key. The issue that I'm facing is when two players is readying themselves, the lobby is only printing out a message for the last player who readied themselves. The system is built up in the following way.
Main Server
package master;
import java.net.*;
import java.io.*;
import java.util.*;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import main.Lobby;
public class MainServer {
public static final int PORT = 4444;
public static final String HOST = "localhost";
public ArrayList<Lobby> serverList = new ArrayList<>();
public static void main(String[] args) throws IOException, ClassNotFoundException {
new MainServer().runServer();
}
public void runServer() throws IOException, ClassNotFoundException {
// Creating the server
ServerSocket serverSocket = new ServerSocket(PORT);
System.out.println("Main Server initiated.");
while (true) {
Socket socket = serverSocket.accept();
try {
// Establishing the connection to the Lobby server and then adding it to its list
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject("Server created successfully.");
Lobby s = (Lobby) objectInputStream.readObject();
this.serverList.add(s);
System.out.println("Server \"" + s.name + "\" added to game list.");
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
The lobby
package main;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.Semaphore;
import master.MainServer;
/**
* The Class Server.
*/
public class Lobby implements Serializable {
private static final long serialVersionUID = -21654L;
public static final int PORT = 4445;
public static final int MAX_USERS = 5000;
public static final String HOST = "localhost";
public String name = "Lobby Server";
public int clientNumber;
public int playerNumberReady = 0;
public boolean allPlayersReady = false;
public boolean OddurIsNice = false;
public static void main(String[] args) throws IOException, ClassNotFoundException {
Lobby s = new Lobby();
s.runServer();
}
public void runServer() throws IOException, ClassNotFoundException {
registerServer();
new Thread( () -> {
try {
ServerSocket serverSocket = new ServerSocket(PORT);
System.out.println("Server waiting for connections...");
while (true) {
Socket socket = serverSocket.accept();
System.out.println("User 1 is now connected");
clientNumber++;
new ObjectOutputStream(socket.getOutputStream()).writeObject("You are connected man");
Socket socket2 = serverSocket.accept();
System.out.println("User 2 is now connected");
clientNumber++;
// ObjectOutputStream objectOutputStream2 = new ObjectOutputStream(socket2.getOutputStream());
// objectOutputStream2.writeObject("You are player number " + clientNumber + ". Waiting for other players to join");
new ServerThread(socket, socket2).start();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}).start();
}
private void registerServer() throws UnknownHostException, IOException, ClassNotFoundException {
// Method for establishing a connection to the MainServer
Socket socket = new Socket(MainServer.HOST, MainServer.PORT);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
objectOutputStream.writeObject(this);
System.out.println((String) objectInputStream.readObject());
}
public class ServerThread extends Thread {
public Socket socket = null;
public Socket socket2 = null;
ServerThread(Socket socket, Socket socket2) {
this.socket = socket;
this.socket2 = socket2;
}
public void run() {
try {
// This method is for when the client want's to connect to the lobby
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
System.out.println("User 1 is now connected");
ObjectInputStream objectInputStream2 = new ObjectInputStream(socket2.getInputStream());
ObjectOutputStream objectOutputStream2 = new ObjectOutputStream(socket2.getOutputStream());
System.out.println("User 2 is now connected");
BoardGameClient joined = (BoardGameClient) objectInputStream.readObject();
System.out.println(joined.name + " is now connected.");
while(true) {
objectOutputStream.writeObject("You joined the server.");
objectOutputStream.writeObject("You are player Number " + 1);
objectOutputStream.writeObject("Press '1' if you are ready");
objectOutputStream2.writeObject("You joined the server.");
objectOutputStream2.writeObject("You are player Number " + 2);
objectOutputStream2.writeObject("Press '1' if you are ready");
if(objectInputStream.readObject().equals(1)) {
playerNumberReady++;
}
if(objectInputStream2.readObject().equals(1)) {
playerNumberReady++;
}
if(playerNumberReady != 2) {
allPlayersReady = false;
} else {
allPlayersReady = true;
}
if (allPlayersReady == false) {
objectOutputStream.writeObject("Waiting...");
objectOutputStream2.writeObject("Waiting...");
}
if (allPlayersReady == true) {
objectOutputStream.writeObject("Lets GO");
objectOutputStream2.writeObject("Lets GO");
}
while (true) {
System.out.println(objectInputStream.readObject());
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
And the client
package main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
import java.util.concurrent.Semaphore;
import master.MainServer;
public class BoardGameClient implements Serializable {
private int playerName;
private static final long serialVersionUID = -6224L;
public String name = "User";
private transient Socket socket;
public transient Scanner input = new Scanner(System.in);
public static void main(String[] args) {
BoardGameClient c = new BoardGameClient();
if (args.length > 0) {
c.name = args[0];
}
try {
c.joinServer();
} catch (ClassNotFoundException | IOException e) {
System.out.println("Failed to join server.");
e.printStackTrace();
}
}
public void joinServer() throws UnknownHostException, IOException, ClassNotFoundException {
socket = new Socket(Lobby.HOST, Lobby.PORT);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
while(true) {
objectOutputStream.writeObject(this);
BufferedReader inputReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println(objectInputStream.readObject());
System.out.println(objectInputStream.readObject());
System.out.println(objectInputStream.readObject());
int ready = input.nextInt();
objectOutputStream.writeObject(ready);
System.out.println(objectInputStream.readObject());
objectOutputStream.writeObject(name + ": " + inputReader.readLine());
}
}
}
I sincerely hope, that someone will be able to help me out <3
Firstly, there's a few things that bug me about this code. Not to sound condescending but you need to avoid rewriting code as much as possible. What happens if you want 3 or more players in the future? Currently you'd have to manually create a whole socket eg socket3, and then rewrite all the code you've already written. This is bad. You've manually spent the time creating 2 sockets and then created 2 streams for both of these sockets etc etc.
This can be automated don't you think?
Secondly, you have a lot of public variables. Unless they are static and final, for the most part you should keep variables as private.
I've tinkered with your lobby class as seen below, which is more scalable. It's not perfect by any means, but I feel illustrates the direction of improvement you should be heading for. Look up SOLID OOP principles, they'll help you guaranteed.
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* The Class Server.
*/
public class Lobby implements Serializable {
private static final long serialVersionUID = -21654L;
public static final int PORT = 4445;
public static final int MAX_USERS = 5000;
public static final String HOST = "localhost";
private static final int MIN_USERS = 2;
private String name = "Lobby Server";
private int clientNumber;
private boolean gameRunning = false;
// set of client connections
private final Set<ServerThread> clientConnectionThreads = new LinkedHashSet<>();
public static void main(String[] args) throws IOException, ClassNotFoundException {
Lobby s = new Lobby();
s.createLobby();
}
public void createLobby() throws IOException, ClassNotFoundException {
// waits for all players to ready up in a different thread
new Thread(this::waitReady).start();
registerServer();
// Listens for clients
runServer();
}
public void runServer() {
// closes serverSocket automatically in this way
try (ServerSocket serverSocket = new ServerSocket(PORT)) {
System.out.println("Server waiting for connections...");
long ids = 0;
while (!gameRunning) {
// accepts a new client connection
Socket socket = serverSocket.accept();
if (clientConnectionThreads.size() >= MAX_USERS) {
// tell user server is full and dont add the connection
} else {
// calculates the new id of the incoming player and adds them to the lobby
ids++;
this.clientConnectionThreads.add(new ServerThread(ids, socket));
System.out.println("User " + ids + " is now connected");
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
/*
* loops until every player is ready and there is enough players and then starts
* the game.
*/
public void waitReady() {
while (true) {
try {
if (areAllReady() && this.clientConnectionThreads.size() >= MIN_USERS) {
startGame();
return;
}
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// returns true if all users are ready
public boolean areAllReady() {
return clientConnectionThreads.stream().allMatch(ServerThread::isReady);
}
public void startGame() {
System.out.println("Starting game...");
this.gameRunning = true;
clientConnectionThreads.forEach(ServerThread::startGame);
// do game stuff
}
// i havent touched this function
private void registerServer() throws UnknownHostException, IOException, ClassNotFoundException {
// Method for establishing a connection to the MainServer
Socket socket = new Socket(MainServer.HOST, MainServer.PORT);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
objectOutputStream.writeObject(this);
System.out.println((String) objectInputStream.readObject());
}
public class ServerThread extends Thread {
private final Socket socket;
private final ObjectInputStream in;
private final ObjectOutputStream out;
private final long id;
boolean ready = false;
private ServerThread(long id, Socket socket) throws IOException {
// does some basic initialization
this.socket = socket;
this.id = id;
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
// starts this connection thread
this.start();
}
public boolean isReady() {
return ready;
}
public void run() {
try {
// sets up the client and waits for their input
BoardGameClient joined = (BoardGameClient) in.readObject();
System.out.println(joined.name + " is now connected.");
out.writeObject("You joined the server.");
out.writeObject("You are player Number " + id);
out.writeObject("Press '1' if you are ready");
out.flush();
// waits for user to return ready
while (!ready) {
try {
int input = in.readInt();
System.out.println("input: " + input);
ready = input == 1;
} catch (ClassCastException e) {
e.printStackTrace();
}
}
out.writeObject("Waiting for players...");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void startGame() {
// send client message etc etc
}
}
public String getName() {
return name;
}
}
I basically didn't change any of the other classes, except a few lines within the client class to make this work. (I've changed the ready input type from writeObject() to writeInt())
I haven't tested this for problems, but I know it works at least on a basic level.
I also suggest using writeUTS()/readUTS() instead of writeObject()/readObject() for sending and receiving Strings across streams as this will add extra complexity to the code.

JAVA Chat app not working over internet

I created a chat app in Java it worked when i open server and clients on different terminals but same computer. Today i gave it to my friend to test it over internet and its not working(Connection timed out ,yes i am using muiltithreads). I have allowed port (i am using 4242) in my firewall and my friends. But still not working.
I have read couple of similar question asked on internet but each has different steps (none working) and also i am not getting all steps though.
Some said that router is hiding my ip address so i need to enable port forwarding (i dont know how) . Also there must be a way without it. Many software works like this but doesnt need us to enable port forwarding. Will using a mobile hotspot instead of modem work(I am so DUMB!).
i am noob in this area, studied networking in JAVA yesterday and made app yesterday night. Help me run my app over internet in simple language. Will be gratefull if it works without port forwarding and static ip address. Let me know if you need to see my code.
Server Side:
import java.io.*;
import java.net.*;
import java.util.*;
class DailyAdviceS
{
ArrayList<PrintWriter> Clients=new ArrayList<PrintWriter>();
Socket sock;
public static void main(String args[])
{
DailyAdviceS ad= new DailyAdviceS();
ad.go();
}
private void go()
{
try
{
ServerSocket server= new ServerSocket(4242);
InetAddress ip;
ip = InetAddress.getLocalHost();
System.out.println("Current IP address : " + ip.getHostAddress());
while(true)
{
sock=server.accept();
PrintWriter writer = new PrintWriter(sock.getOutputStream());
Clients.add(writer);
Thread foundR= new Thread(new nodeR(sock));
foundR.start();
System.out.println("got a connection");
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
private void SendAll(String Chat,String name)
{
Iterator it=Clients.iterator();
while(it.hasNext())
{
try
{
PrintWriter writer= (PrintWriter)it.next();
writer.println(name+" /t "+Chat);
writer.flush();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
class nodeR implements Runnable //recieve message from clients
{
private String hostName;
private BufferedReader reader;
public nodeR(Socket s)
{
try
{
String hostName = s.getInetAddress().getHostName();
System.out.println(hostName);
InputStreamReader in= new InputStreamReader(s.getInputStream());
reader = new BufferedReader(in);
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void run()
{
String Message;
try
{
String Name=InetAddress.getLocalHost().getCanonicalHostName();
SendAll(Name+" Ready","");
while(true)
{
while ((Message=reader.readLine())!=null)
{
SendAll(Message,Name);
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
CLient Side:
import java.io.*;
import java.net.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import javax.swing.text.*;
class DailyAdvice
{
private JTextArea ar= new JTextArea(100,100);
private JTextField field = new JTextField(17);
private JButton button;
private Socket chat;
private InputStreamReader stream;
private BufferedReader reader;
private PrintWriter writer;
public static void main(String args[])
{
DailyAdvice ad= new DailyAdvice();
ad.setnw();
ad.go();
}
private void go()
{
JFrame frame= new JFrame("Chat with RedHead");
JPanel panel= new JPanel();
ar.setLineWrap(true);
ar.setWrapStyleWord(true);
ar.setEditable(false);
JScrollPane scroll= new JScrollPane(ar);
scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
panel.add(field);
DefaultCaret caret = (DefaultCaret) ar.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
button= new JButton("Send");
panel.add(button);
frame.getRootPane().setDefaultButton(button);
frame.add(scroll,BorderLayout.CENTER);
frame.add(panel,BorderLayout.SOUTH);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setBounds(50,50,300,300);
frame.setVisible(true);
Runnable r= new Recieve();
Thread send= new Thread(new Send());
Thread recieve= new Thread(r);
send.start();
recieve.start();
}
private void setnw()
{
try
{
chat = new Socket("122.176.8.153",4242);
stream= new InputStreamReader(chat.getInputStream());
reader= new BufferedReader(stream);
writer = new PrintWriter(chat.getOutputStream());
System.out.println("connection established");
}
catch(Exception e)
{
e.printStackTrace();
}
}
class Send implements Runnable
{
public void run()
{
button.addActionListener(new timetosend());
}
class timetosend implements ActionListener
{
public void actionPerformed(ActionEvent ev)
{
try
{
String msg =field.getText();
writer.println(msg);
writer.flush();
}
catch (Exception ex)
{
ex.printStackTrace();
}
field.setText("");
}
}
}
class Recieve implements Runnable
{
public void run()
{
try
{
String input;
while ((input= reader.readLine())!=null)
{
String[] result=input.split("/t");
ar.append(result[0]+" : "+result[1]+'\n');
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
}
Please make sure your application is not using the private IP to connect to your server if accessing over the internet. you can check your PC's public IP from the site below which is currently allocated to your PC, and can use this in your client apps.
And also make sure you have configure the port in port forwarding in your switch/router and if it is not allowed by your ISP, you can use any port forwarding software on your PC to do that.
http://www.get-myip.com/

Java NIO - SocketChannel.write() on server many times but Client only receive result once

I'm doing an exercise requires making a server - client chat program using Java Non-Blocking IO. At the moment, the way the program works is simple: when a client send a message to the server, the server (which already keep track of all the clients) echo the message back to all the clients.
This is my some parts of my server-side code:
public static ByteBuffer str_to_bb(String msg) {
try {
return encoder.encode(CharBuffer.wrap(msg));
} catch(Exception e) {
e.printStackTrace();
}
return null;
}
private static void broadcastMessage(String nickname, String message) {
System.out.println(">clientSocketChannels size " + clientSocketChannels.size());
Iterator clientSocketChannelsIterator = clientSocketChannels.iterator();
while (clientSocketChannelsIterator.hasNext()) {
SocketChannel sc = (SocketChannel) clientSocketChannelsIterator.next();
try {
ByteBuffer bb = str_to_bb(message);
System.out.println("bufferRemaining: " + bb.remaining()); // returns 2048
int writeResult = sc.write(bb);
System.out.println("writeResult: " + writeResult); // returns 2048
} catch (IOException e) {
e.printStackTrace();
}
}
}
The following is my client-side code:
import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
* Created by ThaiSon on 7/6/2015.
*/
public class ChatRoomClientGUI {
private JTextArea textAreaMessages;
private JTextField textFieldMessage;
private JButton buttonSendMsg;
private JPanel jPanel1;
private JLabel txtFieldInfo;
private static InetAddress inetAddress;
private static final int PORT = 1234;
private static Socket socket = null;
private static Scanner input = null;
private static PrintWriter output = null;
private static ChatRoomClientGUI singleton;
public ChatRoomClientGUI() {
singleton = this;
buttonSendMsg.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
if (e.getButton() == MouseEvent.BUTTON1) {
String message = textFieldMessage.getText();
output.println(message);
textFieldMessage.setText("");
}
}
});
}
public static void main(String[] args) {
JFrame promptFrame = new JFrame();
Object nickname = JOptionPane.showInputDialog(promptFrame, "Enter your nickname:");
promptFrame.dispose();
JFrame frame = new JFrame("ChatRoomClientGUI");
frame.setContentPane(new ChatRoomClientGUI().jPanel1);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
System.out.println("> Client with nickname " + nickname);
try {
inetAddress = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
accessServer(nickname.toString());
}
private static void accessServer(String nickname) {
try {
socket = new Socket(inetAddress, PORT);
input = new Scanner(socket.getInputStream());
output = new PrintWriter(socket.getOutputStream(), true);
output.println(nickname); // Register nickname with the server
//TODO update the txtFieldInfo content
// Create a new thread to listen to InputStream event
InputStreamEvent inputStreamEvent = new InputStreamEvent(socket);
inputStreamEvent.start();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void handleInputStream(){
String response = input.nextLine();
System.out.println("TODO " + response);
singleton.textAreaMessages.append(response + "\n");
}
static class InputStreamEvent extends Thread{
Socket socket;
public InputStreamEvent(Socket socket){
this.socket = socket;
}
public void run(){
try {
InputStream inputStream = socket.getInputStream();
byte[] buffer = new byte[2048];
int read;
while (true){
if(inputStream.available() > 0){
handleInputStream();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
The problem I'm facing with now is that when I use a client (which works well with the old multithreaded server) to send message to the server, the client only get return the first message it sends. All the next responses from the server is empty (the server does send back, but only an empty message).
So my attempts to debug includes:
check if the messages from the client has reach the server or not. They does.
log the buffer.remaining() and socketChannel.write(buffer) result as shown above, all the log result seems to be normal to me.
Hope you guys can help me with this.
This:
if(inputStream.available() > 0){
Get rid of this test. With it, your client is smoking the CPU. Without it, it will block in readLine() as God intended.
Are you sure your server is still sending lines? with line terminators? If it isn't, readLine() will block forever looking for one, until end of stream or an exception occurs.
I referred the code explain by EJP on this link Java NIO Server/Client Chat App - sending data only by closing the socket
it solves my problem. use this code
import java.nio.channels.SocketChannel;
import java.nio.channels.Selector;
import java.nio.ByteBuffer;
import java.io.IOException;
import java.util.Scanner;
import java.nio.channels.SelectionKey;
import java.net.InetSocketAddress;
public class Client {
public static void main(String args[]) {
try {
ByteBuffer buf = ByteBuffer.allocate(200);
Scanner scanner = new Scanner(System.in);
Selector selector = Selector.open();
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_CONNECT|SelectionKey.OP_READ|SelectionKey.OP_WRITE);
boolean isConnected = socketChannel.connect(new InetSocketAddress("localhost", 5000));
if(isConnected) {
System.out.println("Connected, de-registering OP_CONNECT");
}
new Thread(new Runnable(){
private SocketChannel socketChannel;
private Selector selector;
public Runnable init(SocketChannel socketChannel, Selector selector) {
this.socketChannel = socketChannel;
this.selector = selector;
return this;
}
public void run() {
try {
ByteBuffer buf = ByteBuffer.allocate(200);
while(!Thread.interrupted()) {
int keys = selector.select();
if(keys > 0) {
for(SelectionKey key : selector.selectedKeys()) {
if(key.isConnectable()) {
boolean finishConnectResult = socketChannel.finishConnect();
socketChannel.register(this.selector, SelectionKey.OP_WRITE|SelectionKey.OP_READ);
System.out.println("Finished Connect : " + finishConnectResult);
}
if(key.isReadable()) {
int bytesRead = 0;
while((bytesRead = socketChannel.read(buf)) > 0) {
buf.flip();
while(buf.hasRemaining()) {
System.out.print((char)buf.get());
}
buf.clear();
}
if(bytesRead == -1) {
key.channel().close();
}
}
}
}
Thread.sleep(10);
}
} catch(IOException e) {
e.printStackTrace();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}.init(socketChannel, selector)).start();
while(true) {
while(scanner.hasNextLine()) {
buf.clear();
buf.put(scanner.nextLine().getBytes());
buf.flip();
socketChannel.write(buf);
buf.flip();
}
}
} catch(IOException e) {
e.printStackTrace();
}
}
}
I have done the mistake setting this flag
key.interestOps(SelectionKey.OP_READ);
)
instead of below.
use this
socketChannel.register(this.selector, SelectionKey.OP_WRITE|SelectionKey.OP_READ);

chat in java not synchronized (sockets, threads)

I'm trying to figure out a way to get an instance of a server to negotiate between two clients by creating a chat thread between them.
I created this project, and it "almost" works... but it seems like there is a buffer of synch problem.
when writing a line in one side (i.e Client#1), it doesn't pass to the other side (i.e Client#2), but only after Client#2 trys to pass a line too.
I know there might be better ways to implement this, but I'd like to understand what's wrong with my code.
your help would be great!
the code:
server
import java.io.*;
import java.net.*;
public class Server
{
public static void main(String[] args)
{
int id = 1;
System.out.println();
System.out.println("Server");
try
{
ServerSocket serverSocket = new ServerSocket(4321);
while (true)
{
Socket client1Socket = serverSocket.accept();
Socket client2Socket = serverSocket.accept();
System.out.println("clients connected from ports: \n"
+ client1Socket.getPort() + ", " + client2Socket.getPort());
Thread client1Thread = new ServerThread(client1Socket, client2Socket, id);
client1Thread.start();
id++;
Thread client2Thread = new ServerThread(client2Socket, client1Socket, id);
client2Thread.start();
id++;
}
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
}
server thread
import java.io.*;
import java.net.*;
import java.util.*;
public class ServerThread extends Thread
{
Socket sourceSocket;
Socket destSocket;
int id;
public ServerThread(Socket src, Socket dst, int n)
{
sourceSocket = src;
destSocket = dst;
id = n;
}
public void run()
{
try
{
Scanner clientInput = new Scanner(sourceSocket.getInputStream());
PrintStream destOutput = new PrintStream(destSocket.getOutputStream());
destOutput.println("You are chatting with Client " + id);
boolean more = true;
while (more)
{
String input = clientInput.nextLine();
destOutput.println(input);
if (input.equals("Q"))
{
more = false;
}
}
sourceSocket.close();
destSocket.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
client
import java.io.*;
import java.net.*;
import java.util.*;
public class Client
{
public static void main(String[] args)
{
System.out.println();
System.out.println("Client");
try
{
Socket clientSocket = new Socket("localhost", 4321);
System.out.println("Connection Established");
Scanner input = new Scanner(clientSocket.getInputStream());
PrintStream output = new PrintStream(clientSocket.getOutputStream());
Scanner in = new Scanner(System.in);
System.out.println(input.nextLine());
boolean more = true;
while (more)
{
String text = in.nextLine();
output.println(text);
String nextInput = input.nextLine();
if (nextInput == null)
{
more = false;
}
else
{
System.out.println(nextInput);
}
}
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
In your client code, the line String text = in.nextLine(); will block your thread. That means if you never type in anything in your client, you can not receive anything. So the solution is to put your message receiving code in another thread. such as:
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
while (!Thread.interrupted()) {
System.out.println(input.nextLine());
}
}
});
thread.start();
while (true)
{
String text = in.nextLine();
output.println(text);
// String nextInput = input.nextLine();
......................
}

Categories

Resources