i am trying to create a simple chat app using java sockets, the server is threaded, when a client connects its socket is added to an ArrayList, so that i can send to all in that list.
the problem is when 3 clients are connected, the for loop that sends doesn't work properly, for ex : client 0 sends to both 1 and 2 but client 2 doesn't send to anyone :(
The server and the ClientHandler :
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;
public class MainServer {
private static int portnumber = 6968;
static ArrayList <ClientHandler> allClients = new ArrayList<>();
public static void main(String[] args) throws Exception {
// init
// server works by default on localhost
ServerSocket serversocket = new ServerSocket(portnumber);
int clientNo = 0;
System.out.println("server is running on port : " + portnumber);
while (true) {
// creating a socket for each connection
Socket clientsocket = null;
try {
// receiving incoming requests from users/clients
clientsocket = serversocket.accept();
// input and output from client
PrintWriter out = new PrintWriter(clientsocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(clientsocket.getInputStream()));
// create a threads
ClientHandler ch = new ClientHandler(clientsocket, "Client#" + clientNo, in, out);
// adding to the clientList
allClients.add(ch);
System.out.println(ch.clientName + " has joined");
Thread clientThread = new Thread(ch);
clientThread.start();
// decrease when user leaves
clientNo++;
} catch (Exception e) {
clientsocket.close();
e.printStackTrace();
System.exit(1);
//out.close();
//in.close();
//clientSocket.close();
//serverSocket.close();
}
}
}
}
// handle client requests
public class ClientHandler implements Runnable{
public String clientName;
public Socket clientsocket = null;
public boolean active = false;
private BufferedReader inp;
private PrintWriter out;
private final String EXIT_STR = "exit";
public Scanner clientSc = new Scanner(System.in);
public ClientHandler(Socket socket, String name, BufferedReader inp, PrintWriter out) {
this.clientsocket = socket;
this.clientName = name;
this.inp = inp;
this.out = out;
// active when the thread is created
this.active = true;
}
#Override
public void run() {
// getting the output temp
String recivedMsg = "";
while (true) {
try {
recivedMsg = inp.readLine();
System.out.println(recivedMsg);
// check for ctrl+C
if (recivedMsg.equals(this.EXIT_STR)){
// send to all
System.out.println(this.clientName + " exits");
// close the connection and break
this.active = false;
this.clientsocket.close();
// bye
break;
}
// send to all except me
for (ClientHandler client : MainServer.allClients){
if (!client.clientName.equals(this.clientName)){
client.out.println(this.clientName + ":" + recivedMsg);
client.out.flush();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
try {
// clean
this.clientsocket.close();
this.inp.close();
this.out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
The client :
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class Client {
private String hostName;
private int portNumber;
// set connction and server
public PrintWriter out = null;
public BufferedReader in = null;
public Socket clientSocket = null;
Client(String hostName, int port) {
this.hostName = hostName;
this.portNumber = port;
// setting the connction
this.setConnection();
}
private void setConnection () {
try {
this.clientSocket = new Socket(this.hostName, this.portNumber);
this.out = new PrintWriter(this.clientSocket.getOutputStream(), true);
this.in = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
public void sendMessageToServer(String msg) {
//System.out.println("The msg is : " + msg);
out.println(msg);
}
public String readMessage() {
String outputMsg = "";
try {
outputMsg = in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return outputMsg;
}
// shit cleaning
public void closeSession(){
try {
this.out.close();
this.in.close();
this.clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
System.out.println("Session has been terminated!");
}
public static void main(String args[]) throws IOException{
// init
String host = "localhost";
int port = 6968;
Client newClient = new Client(host, port);
// // send a message
Scanner sc = new Scanner(System.in);
Thread sendMsg = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
String userInput = sc.nextLine();
newClient.sendMessageToServer(userInput);
if (userInput.equals("exit")) {
System.exit(1);
}
} catch (Exception e) {
System.exit(1);
}
}
}
});
Thread getMsg = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
String msgRead = "";
try {
msgRead = newClient.readMessage();
System.out.println(msgRead);
} catch (Exception e) {
System.exit(1);
}
}
}
});
sendMsg.start();
getMsg.start();
}
}
I think the problem is here :
// send to all except me
for (ClientHandler client : MainServer.allClients){
if (!client.clientName.equals(this.clientName)){
client.out.println(this.clientName + ":" + recivedMsg);
client.out.flush();
break;
}
}
The fix is straightforward: remove the break statement from the loop where you think the problem is.
This break statement causes the loop through all the ClientHandlers to stop as soon as it sends the message to one client. You don't want this: you want this loop to keep going and send the message to all clients other than the one that wrote the message.
Related
I'm a beginner in programming and do strugle a bit.
So I'm building a TCP peer to peer Chat and that requires me to divide the tasks -> Threads.
So I want to built a Thread for the "writing" part of that connection (Scanner, DataOutputStream etc.) In order to do that i implemented Runnable and that forces me to write my Thread in the overwritten run() method.
Now I have a bit of a problem, because in Order to send my messages out to the "other end (another client) I need the "socket.getOutputStream" but I cant use it in the run() method and i dont know how to fix this problem, sitting already a week on this problem. Any ideas ?
public class ClientHorcher implements Runnable {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(11111);
System.out.println("Waiting For Connection:-");
Socket socket = serverSocket.accept();
Scanner scanner = new Scanner(System.in);
DataInputStream datenRein = new DataInputStream(socket.getInputStream());
DataOutputStream datenRaus = new DataOutputStream(socket.getOutputStream());
String nickname;
System.out.print("Gib einen Nickname ein: ");
nickname = scanner.nextLine();
while (true) {
String vonMsg = datenRein.readUTF(in);
System.out.println("Client:-" + vonMsg);
if (vonMsg.equals("exit")) {
System.out.println("Beenden!!!");
datenRein.close();
datenRaus.close();
scanner.close();
socket.close();
serverSocket.close();
System.exit(0);
}
System.out.print(nickname + ":-");
String zuMsg = scanner.nextLine();
datenRaus.writeUTF(zuMsg);
if (zuMsg.equals("exit")) {
System.out.println("Quiting!!!");
datenRein.close();
datenRaus.close();
scanner.close();
socket.close();
serverSocket.close();
System.exit(0);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
}
}`
`public class ClientVerbinder implements Runnable {
public static void main(String[] args) {
try {
Socket socket = new Socket("Localhost", 11111);
System.out.println("Connected");
Scanner scanner = new Scanner(System.in);
DataInputStream datenRein = new DataInputStream(socket.getInputStream());
DataOutputStream datenRaus = new DataOutputStream(socket.getOutputStream());
String nickname;
System.out.print("Gib einen Nickname ein: ");
nickname = scanner.nextLine();
while (true) {
System.out.print(nickname+":-");
String zuMsg = scanner.nextLine();
datenRaus.writeUTF(zuMsg);
if (zuMsg.equals("exit")) {
System.out.println("Beenden!!!");
datenRein.close();
datenRaus.close();
scanner.close();
socket.close();
System.exit(0);
}
String vonMsg = datenRein.readUTF();
System.out.println("CLient"+":-" + vonMsg);
if (vonMsg.equals("exit")) {
System.out.println("Quiting!!!");
datenRein.close();
datenRaus.close();
scanner.close();
socket.close();
System.exit(0);
}
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
}
}
Multiple possibilities.
Use static variables. Normally you would not do that, but because your code is all-static, you could
Use member variables in an OO-style code.
If you wanted to do it properly, you'd split the server into two parts:
The ServerSocket listener that only listens to connections (Socket connectionToClient = ss.accept), and whenever a connection comes in, creates a new
ClientHandler, passes in the Socket, and the ClientHandler then starts its own thread internally
This way, the ClientHandler has all the data it needs (again as member variables) and can work on its own concerns (aka 'separation of concerns).
Update
This is what I created. Really simple.
Start Server
Start 1st client
Start 2nd client
In any client, type message
Other client receives it
Classes:
SimpleServer
package stackoverflow.simplemtserver;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.LinkedBlockingDeque;
public class SimpleServer { // make it closeable and close sockets if this is not standalone
public static void main(final String[] args) throws IOException {
final int port = 7623;
new SimpleServer(port);
}
final LinkedBlockingDeque<SimpleServerClientHandler> clientHandlers = new LinkedBlockingDeque<>();
private final ServerSocket mServerSocket;
public SimpleServer(final int pPort) throws IOException {
mServerSocket = new ServerSocket(pPort);
final Thread m = new Thread(() -> runLoop(), getClass().getSimpleName() + " Main Loop");
m.start();
}
private void runLoop() {
while (true) {
try {
System.out.println("Server waiting for connection...");
#SuppressWarnings("resource") final Socket cs = mServerSocket.accept(); // do NOT close the socket here, no try-resource, will interrupt threaded communication!
final SimpleServerClientHandler ch = new SimpleServerClientHandler(this, cs);
clientHandlers.add(ch);
System.out.println("Connection accepted, handler started. Handlers active: " + clientHandlers.size());
} catch (final IOException e) {
// handle this how you need it
e.printStackTrace();
}
}
}
public void signOffClientHandler(final SimpleServerClientHandler pClientHandler) {
clientHandlers.remove(pClientHandler); // we could also accommplish this using stack trace to avoid access from outside, but this is the easier solution
}
public void spreadMessageToClients(final String pMessageFromClient, final SimpleServerClientHandler pSimpleServerClientHandler) {
for (final SimpleServerClientHandler ch : clientHandlers) {
if (ch != pSimpleServerClientHandler) ch.relayMessageToClient(pMessageFromClient); // we can work with identity == and != here
}
}
}
SimpleServerClientHandler
package stackoverflow.simplemtserver;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class SimpleServerClientHandler {
private final SimpleServer mParentServer;
private final Socket mClientSocket;
private final DataInputStream mDIS;
private final DataOutputStream mDOS;
public SimpleServerClientHandler(final SimpleServer pSimpleServer, final Socket pCS) throws IOException {
mParentServer = pSimpleServer;
mClientSocket = pCS;
mDIS = new DataInputStream(mClientSocket.getInputStream());
mDOS = new DataOutputStream(mClientSocket.getOutputStream());
final Thread t = new Thread(() -> runComms(), getClass().getSimpleName() + " Comms Loop");
t.setDaemon(true); // threads now stop once server stops. this is NOT a soft exit
t.start();
}
private void runComms() {
try {
try {
while (true) {
// do all your logic here, work with DIS and DOS
final String messageFromClient = mDIS.readUTF();
if (messageFromClient == null) break;
if (!messageFromClient.startsWith("*")) mParentServer.spreadMessageToClients(messageFromClient, this);
}
} catch (final Exception e) {
// TODO: handle exception
}
} finally {
try {
mClientSocket.close(); // also closes DataIn/Out
} catch (final IOException e) { /* ignore */ }
mParentServer.signOffClientHandler(this);
}
}
public void relayMessageToClient(final String pMessageFromClient) {
try {
mDOS.writeUTF("*" + pMessageFromClient);
} catch (final IOException e) {
// ignore unless needed otherwise
}
}
}
SimpleClient
package stackoverflow.simplemtserver;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;
public class SimpleClient {
public static void main(final String[] args) throws UnknownHostException, IOException {
final String hostname = "localhost";
final int port = 7623;
try (final Socket s = new Socket(hostname, port);
final DataInputStream dis = new DataInputStream(s.getInputStream());
final DataOutputStream dos = new DataOutputStream(s.getOutputStream());
final Scanner scanner = new Scanner(System.in);) {
final Thread t = new Thread(() -> runListenerLoop(dis), SimpleClient.class.getSimpleName() + " Reader Thread");
t.setDaemon(true);
t.start();
while (true) {
System.out.println("Enter message:");
System.out.flush();
final String msg = scanner.nextLine();
if (msg == null) break;
System.out.println("Spreading message: " + msg);
dos.writeUTF(msg);
}
}
}
private static void runListenerLoop(final DataInputStream pDis) {
while (true) {
try {
System.out.println("Waiting for incoming messages...");
final String msg = pDis.readUTF();
System.out.println("Received: " + msg);
} catch (final SocketException e) {
// if ("java.net.SocketException: Connection reset".equals(e.getMessage()))
break;
} catch (final IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
From here on, there's now more ways you can extend this client/server communication:
use opcodes (read/write int constants or enums before data) to distinguish for special operations and/or messages (like this here puts an asterisk in front of the string to prevent re-re-laying the same message indefinitely over the network)
read multiple strings for user, message, additional options
implement this is a user friendly UI so you dont have to use console I/O
Update 2
The pure peer-to-peer solution is this one.
If the app is run without params, it goes into listening mode, waiting for a connection.
If the app is run with one arguments, it interprets it as listening port and also goes into listening mode.
If the app is un with [hostname] [port] arguments, it will try to connect there
Example:
start first app without arguments (listening)
start second app with arguments "localhost 7642" (connecting)
both apps will now
connect,
then set up I/O resources,
then start the listening thread for incoming messages
then go into the read-keyboard-and-write-to-socket loop
now you can type a message in one of the apps, the other one will receive it
p2p code:
package stackoverflow.simplemtserver;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;
public class SimplePeerToPeerClient {
static public final int DEFAULT_PORT = 7642;
public static void main(final String[] args) throws UnknownHostException, IOException {
if (args.length == 0) {
System.out.println("Waiting on default port " + DEFAULT_PORT);
waitForConnection(DEFAULT_PORT);
} else if (args.length == 1) {
final int port = Integer.parseInt(args[0]);
System.out.println("Waiting on port " + port);
waitForConnection(port);
} else if (args.length == 2) {
final String hostName = args[0];
final int port = Integer.parseInt(args[1]);
System.out.println("Connecting to " + hostName + " on port " + port);
connectToOtherSide(hostName, port);
} else throw new IllegalArgumentException("Invalid amount of argument! Need none (listen) or 2: [hostname] [port] (connect)");
}
private static void waitForConnection(final int pPort) throws IOException {
try (final ServerSocket ss = new ServerSocket(pPort);) {
#SuppressWarnings("resource") final Socket socket = ss.accept(); // will get closed later
startComms(socket);
} // closes ServerSocket after 1st connection
}
private static void connectToOtherSide(final String pHostName, final int pPort) throws UnknownHostException, IOException {
#SuppressWarnings("resource") final Socket socket = new Socket(pHostName, pPort); // will get closed later
startComms(socket);
}
private static void startComms(final Socket pSocket) throws IOException {
try (
final DataInputStream dis = new DataInputStream(pSocket.getInputStream());
final DataOutputStream dos = new DataOutputStream(pSocket.getOutputStream());
final Scanner scanner = new Scanner(System.in);) {
// run the listener loop
final Thread t = new Thread(() -> runListenerLoop(dis), SimpleClient.class.getSimpleName() + " Reader Thread");
t.setDaemon(true);
t.start();
// run my keyboard-input-send loop
while (true) {
System.out.println("Enter message:");
System.out.flush();
final String msg = scanner.nextLine();
if (msg == null) break; // empty input ends client
System.out.println("Spreading message: " + msg);
dos.writeUTF(msg);
}
} finally {
try {
pSocket.close();
} catch (final IOException e) { /* ignore */ }
}
}
private static void runListenerLoop(final DataInputStream pDis) {
while (true) {
try {
System.out.println("Waiting for incoming messages...");
final String msg = pDis.readUTF();
System.out.println("Received: " + msg);
} catch (final SocketException e) {
// if ("java.net.SocketException: Connection reset".equals(e.getMessage()))
break;
} catch (final IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
I want to create simple communicator with one server and few clients who could connect and send data to it. It works fine without any threads, with only one client, but once i try to incorporate concurrency it doesn't work. From client perspective there is some connection, I can send data, but there is no sign of receiving that data on server. Here is the server class:
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
public class MyServerSocket implements Runnable
{
private ServerSocket serverSocket;
public MyServerSocket() throws Exception
{
Random generator = new Random();
this.serverSocket = new ServerSocket(generator.nextInt(65000 - 60000) + 60000, 50, InetAddress.getByName("192.168.0.105"));
}
public InetAddress getSocketIPAddress()
{
return this.serverSocket.getInetAddress();
}
public int getPort()
{
return this.serverSocket.getLocalPort();
}
public void run()
{
while (true)
{
System.out.println("Running a thread");
try
{
String data = null;
Socket client = this.serverSocket.accept();
String clientAddress = client.getInetAddress().getHostName();
System.out.println("Connection from: " + clientAddress);
System.out.println("Here I am");
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
String message = "";
while ((data = in.readLine()) != null && data.compareToIgnoreCase("quit") != 0)
{
message = ("\r\nMessage from " + clientAddress + ": " + data);
System.out.println(message);
out.write(message);
}
} catch (Exception e)
{
System.out.println("Something went wrong");
} finally
{
try
{
serverSocket.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
}
}
Server main:
import java.lang.Thread;
public class Main
{
public static void main(String[] args)
{
try
{
MyServerSocket socket = new MyServerSocket();
Runnable runnable = new MyServerSocket();
System.out.println("Port number: " + socket.getPort() + " IP address: " + socket.getSocketIPAddress());
Thread thread = new Thread(runnable);
thread.start();
}catch (Exception e)
{
e.printStackTrace();
}
}
}
Client class:
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
public class ClientSocket
{
private Socket socket;
private Scanner scanner;
ClientSocket(InetAddress serverAddress, int serverPort) throws Exception
{
this.socket = new Socket(serverAddress, serverPort);
this.scanner = new Scanner(System.in);
}
public void sendData() throws Exception
{
String data;
System.out.println("Please type in the message. If you want to terminate the connection, type Quit");
PrintWriter out = new PrintWriter(this.socket.getOutputStream(), true);
do
{
data = scanner.nextLine();
out.println(data);
out.flush();
}while(data.compareToIgnoreCase("quit") != 0);
out.println();
}
}
Client main:
import java.net.InetAddress;
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
Scanner scanner = new Scanner(System.in);
int port;
System.out.println("Provide port at which you will communicate with the server");
port = scanner.nextInt();
try
{
ClientSocket socket1 = new ClientSocket(InetAddress.getByName("192.168.0.105"), port);
socket1.sendData();
}catch(Exception e)
{
System.out.println("Could not connect to the server.");
}
}
}
Server somehow stops its working when is about to accept the client connection, while client works fine and seem to be connected to the server.
In server side, once you accept a client connection, you should new a thread to process this connection:
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
public class MyServerSocket implements Runnable {
private ServerSocket serverSocket;
public MyServerSocket() throws Exception {
Random generator = new Random();
this.serverSocket = new ServerSocket(generator.nextInt(65000 - 60000) + 60000, 50, InetAddress.getByName("192.168.0.105"));
}
public InetAddress getSocketIPAddress() {
return this.serverSocket.getInetAddress();
}
public int getPort() {
return this.serverSocket.getLocalPort();
}
public void run() {
while (true) {
System.out.println("Running a thread");
try(Socket client = this.serverSocket.accept()) {
// new thread to process this client
new Thread(() -> {
try {
String data = null;
String clientAddress = client.getInetAddress().getHostName();
System.out.println("Connection from: " + clientAddress);
System.out.println("Here I am");
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
String message = "";
while (true) {
if (!((data = in.readLine()) != null && data.compareToIgnoreCase("quit") != 0)) break;
message = ("\r\nMessage from " + clientAddress + ": " + data);
System.out.println(message);
out.write(message);
}
} catch (IOException e) {
System.out.println("Something went wrong");
}
}).start();
} catch (Exception e) {
System.out.println("Something went wrong");
}
}
}
}
Ok, somehow I solved that problem, but still I need to understand how does it work:
Accepting connection inside try block, without finally block (nor try with resources) so socket is opened all the time.
Modified main method so there is no threads or runnable objects at all in it. The whole process is done within the class:
Code:
public class Main
{
public static void main(String[] args)
{
try
{
MyServerSocket socket = new MyServerSocket();
System.out.println("Port number: " + socket.getPort() + " IP address: " + socket.getSocketIPAddress());
socket.run();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
If anyone could point me out mistakes that are still in this final version of code I'll be grateful.
I have made a basic chat application which runs fine on the same PC but I want it to work on different machines as well.
For the sake of simplicity, I have omitted the GUI code. I receive the IP, name, and port from a separate application which passes it to the client's constructor. I have entered the IP and port of the machine on which the server is running.
Client
public class ClientGui extends JFrame implements Runnable, KeyListener, ActionListener
{
private JPanel contentPane;
private Socket socket;
private String name , ip;
private int port;
private JTextField input;
private JTextArea console;
private JButton send;
private String message;
private DateFormat format;
private BufferedReader in;
private PrintWriter out;
private String reply;
public ClientGui(String name, String ip, int port)
{
format = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT);
this.name = name;
this.ip = ip;
this.port = port;
new Thread(this).start();
}
public void run()
{
try {
socket = new Socket(ip, port);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
while (true) {
out.println(name);
reply = in.readLine();
if (reply.equals("NAME")) {
name = JOptionPane.showInputDialog("Name taken , Enter another");
} else {
input.setEditable(true);
setTitle(name);
break;
}
}
while (true) {
reply = in.readLine();
if (reply.startsWith("MESSAGE")) {
log(reply.substring(7));
}
}
} catch (Exception e) {
try {
out.close();
in.close();
socket.close();
} catch (Exception e2) {
dispose();
System.exit(0);
}
dispose();
System.exit(0);
}
}
}
Server
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashSet;
public class Server implements Runnable
{
private static ArrayList<PrintWriter> writers;
private static HashSet<String> names;
private Socket socket;
private String name;
private String message;
public Server(Socket socket)
{
this.socket = socket;
}
public void run()
{
PrintWriter temp = null;
try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
try (PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
while (true) {
name = in.readLine();
if (names.contains(name)) {
out.println("NAME");
} else {
out.println("NAMEACCEPTED");
names.add(name);
break;
}
}
writers.add(out);
temp = out;
while(true) {
message = in.readLine();
for (PrintWriter writer : writers) {
writer.println("MESSAGE" + name + " : " + message);
}
}
}
} catch (Exception e) {
try {
names.remove(name);
writers.remove(temp);
socket.close();
} catch (Exception ignored) {
}
}
}
public static void main(String[] args)
{
writers = new ArrayList<>();
names = new HashSet<>();
ServerSocket server = null;
try {
int port = Integer.parseInt(args[0]);
server = new ServerSocket(port);
} catch (Exception e) {
System.out.println("Enter a valid port");
System.exit(0);
}
while (true) {
try {
System.out.println("Waiting for clients....");
new Thread(new Server(server.accept())).start();
System.out.println("Client Received");
} catch (Exception e) {
System.out.println("Server can't accept clients");
break;
}
}
}
}
I think it could be, because
1) you haven't installed the rigth jre-Version on both devices
2) you aren't in the same Network or you haven't forwarded you'r Ip
have you tried to use this in a Virtual box?
(client1 == vbox1, Server == Computer, client2 == vbox2)
hopefully, this helped
Sorry about the inconvenience to all
the problem was with the port i was using when i switched it , it worked on different machines
thanks for all your help
Good day, I'm trying to create a Client/Server chat, that the 1st client send message to server and the server send it to client 2 and vice versa, but the server is just receiving from 1st client only and not from 2nd.
and also, how can i send messages from client 1 to 2 & vice versa
package s;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
public class Client
{
public static void main(String[] args) throws IOException, Throwable
{
Socket s;
BufferedReader in;
PrintWriter out;
Scanner sc = new Scanner(System.in);
s = new Socket(InetAddress.getLocalHost(),9000);
System.out.println("Connection pending");
in = new BufferedReader (new InputStreamReader(s.getInputStream()));
out = new PrintWriter(s.getOutputStream());
String msg = in.readLine();
System.out.println(msg);
while(msg!="")
{
msg = sc.nextLine();
out.println(msg+"\n");
out.flush();
}
s.close();
sc.close();
}
}
=============================================
package s;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class TClient extends Thread
{
private int num;
private Socket s;
private BufferedReader in;
private PrintWriter out;
public Socket getS()
{
return s;
}
public BufferedReader getIn()
{
return in;
}
public PrintWriter getOut()
{
return out;
}
public TClient(Socket s,int num) throws IOException
{
this.s = s;
this.setNum(num);
System.out.println("Client"+num);
out = new PrintWriter(s.getOutputStream());
in = new BufferedReader (new InputStreamReader(s.getInputStream()));
out.println("Connected"+num+"\n");
out.flush();
}
public void run()
{
while(true)
{
try
{
String msg="";
msg = in.readLine();
System.out.println(msg);
if (msg.equals(".")) break;
}
catch (IOException e)
{
}
}
try
{
s.close();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public int getNum()
{
return num;
}
public void setNum(int num)
{
this.num = num;
}
}
========================================================
package s;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server
{
public static void main(String[] args)
{
ServerSocket ss ;
Socket s = null ;
int nb_clients = 0;
String msg = "";
TClient[] connexions = new TClient[2];
try
{
ss = new ServerSocket(9000);
System.out.println("Server is listening in:"+ss.getLocalPort());
boolean continu = false;
while(!continu)
{
s = ss.accept();
connexions[nb_clients] = new TClient(s,nb_clients+1);
connexions[nb_clients].start();
nb_clients++;
if (nb_clients>=2) continu=true;
}
System.out.println("Clients connected");
s.close();
ss.close();
}
catch(IOException e)
{
}
}
}
========================================
and the output of each terminal is :
Server is listening in:9000
Client1
Client2
Clients connected
and the output of the 2 clients are :
Connection pending
Connected1
Connection pending
Connected2
if i write a message from 1 & 2 to the server, the server output will be like this:
Server is listening in:9000
Client1
Client2
Clients connected
111111111111111111111111111111111111
================================================================
UPDATE :
i changed a condition in server
if (nb_clients>2) continu=true;
and now i can recieve from both clients, now i have to know how i make them communicate between the clients
Solution for two clients.
Sending messages from one client to another client.
The server will have to marshall the messages between the clients.
public class Server
{
static TClient[] connexions = new TClient[2];
public static void send(int clientNum, String message) {
TClient t = connexions[clientNum];
if(t != null) {
t.getOut().println(message);
t.getOut().flush();
}
}
}
In TClient added:
public void sendMessage(String message) {
int client = (getNum()-1)==1 ? 0:1;
Server.send(client, message);
System.out.printf("Sending message(%s) to client:%d from client:%d%n",message,client,getNum());
}
which I added a call to inside your while loop.
In Client I used another thread for receiving message from the server called ReceiveMessageThread:
public class Client
{
public static void main(String[] args) throws IOException, Throwable
{
Socket s;
BufferedReader in;
PrintWriter out;
Scanner sc = new Scanner(System.in);
s = new Socket(InetAddress.getLocalHost(), 9000);
System.out.println("Connection pending");
in = new BufferedReader(new InputStreamReader(s.getInputStream()));
out = new PrintWriter(s.getOutputStream());
ReceiveMessageThread thread = new ReceiveMessageThread(in);
String msg = in.readLine();
System.out.println(msg);
thread.start();
while (msg != "")
{
msg = sc.nextLine();
out.println(msg + "\n");
out.flush();
}
s.close();
sc.close();
}
public static class ReceiveMessageThread extends Thread
{
private BufferedReader in;
public ReceiveMessageThread(BufferedReader in)
{
this.in = in;
}
public void run()
{
while (true)
{
try
{
String message = readMessage(in);
if (message != null && !message.equals(""))
System.out.println(message);
} catch (IOException ie)
{
ie.printStackTrace();
}
}
}
public String readMessage(BufferedReader in) throws IOException
{
String msgreceived = "";
String readValue = "";
while (in.ready())
{
readValue = in.readLine();
if (readValue != null)
msgreceived += readValue;
}
return msgreceived;
}
}
}
in server i changed :
if (nb_clients>2) continu=true;
and the server reads from different clients.
I am working on multi chat in java. I'm kinda new to this socket thing.
There is a problem with my code but I can't find it. I think the problem is in clientSocket.getInputStream(); . I inserted System.out.println before and after this statement. I can't see the second one. It seems that client can connect to port but cannot get inputs from server. If you can help me, I really would be thankful. It has been 3 hours but still I can't find the problem
ClientSide.java
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class ClientSide
{
public Socket clientSocket;
public ObjectOutputStream outStream;
public ObjectInputStream inStream;
public String receiveMessage=null,sendMessage=null;
public GuiScreen gui;
public void run()
{
try
{
clientSocket = new Socket("localhost", 2222);
inStream = new ObjectInputStream(clientSocket.getInputStream());
outStream = new ObjectOutputStream(clientSocket.getOutputStream());
outStream.flush();
while(true)
{
try
{
receiveMessage = (String)inStream.readObject();
gui.appendMessage(receiveMessage);
}
catch(ClassNotFoundException classNot)
{System.err.println("data received in unknown format");}
}
}
catch(UnknownHostException unknownHost)
{System.err.println("You are trying to connect to an unknown host!");}
catch(IOException ioException)
{ioException.printStackTrace();}
}
public String readMessage()
{
String text = "";
try
{
text = (String)inStream.readObject();
}
catch (ClassNotFoundException | IOException e)
{e.printStackTrace();}
return text;
}
public void sendMessage(String msg)
{
try
{
outStream.writeObject(msg);
outStream.flush();
}
catch(IOException ioException){ioException.printStackTrace();}
}
public ClientSide()
{}
private void showGui()
{
gui = new GuiScreen(this,"Client Side");
}
public static void main(String[] args)
{
ClientSide client = new ClientSide();
client.showGui();
client.run();
}
}
MultiCheatServer.java
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class MultiChatServer
{
public static ClientThread[] clientThreads = new ClientThread[10];
public static int portNumber = 2222;
public static ServerSocket serverSocket = null;
public static Socket clientSocket = null;
public static void openPort()
{
try
{
serverSocket = new ServerSocket(portNumber);
}
catch (IOException e)
{e.printStackTrace();}
}
public static void connectToClients()
{
while(true)
{
try
{
clientSocket = serverSocket.accept();
}
catch (IOException e)
{e.printStackTrace();}
for(int i = 0; i<=9; ++i)
{
if(clientThreads[i] == null)
{
clientThreads[i] = new ClientThread(clientSocket,clientThreads);
clientThreads[i].start();
break;
}
}
}
}
public static void main(String[] args)
{
openPort();
connectToClients();
}
}
ClientThread.java
import java.io.DataInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.net.Socket;
public class ClientThread extends Thread
{
public ObjectInputStream inStream = null;
public ObjectOutputStream outStream = null;
public Socket clientSocket;
public ClientThread[] clientThreads;
public ClientThread (Socket cSocket,ClientThread[] cThreads)
{
clientSocket = cSocket;
clientThreads = cThreads;
}
public void sendMessage(String msg)
{
try
{
outStream.writeObject(msg);
outStream.flush();
}
catch (IOException e)
{e.printStackTrace();}
}
public String readMessage()
{
String text = null;
try
{
text = (String)inStream.readObject();
}
catch (ClassNotFoundException | IOException e)
{e.printStackTrace();}
return text;
}
public void run()
{
String text;
String name;
try
{
inStream = new ObjectInputStream(clientSocket.getInputStream());
outStream= new ObjectOutputStream(clientSocket.getOutputStream());
outStream.flush();
sendMessage("Name:\n");
name = readMessage().trim();
sendMessage("type /quit if you want to quit\n");
for(int i = 0 ; i <=9 ; ++i)
if(clientThreads[i]!=null && clientThreads[i]!=this)
clientThreads[i].sendMessage(name + "has come\n");
while(true)
{
text = readMessage() ;
if(text.startsWith("/quit"))
break;
for(int i = 0; i<=9; ++i)
if(clientThreads[i] != null)
clientThreads[i].sendMessage("<" + name + ">" + text);
}
for(int i = 0 ;i<=9; ++i)
if(clientThreads[i]!=null && clientThreads[i]!=this)
clientThreads[i].sendMessage(name + " has disconnected\n");
sendMessage("Bye\n");
inStream.close();
outStream.close();
for(int i = 0;i<=9;++i)
if(clientThreads[i]==this)
clientThreads[i] = null;
}
catch (IOException e)
{e.printStackTrace();}
}
}
One problem I see is that you have to decide who creates the input stream first, the server or the client.
ObjectInputStream tries to read a serialization header in its constructor, and if the output stream has not written it yet it will wait. Now both client and server are waiting for the other to "speak" first.