Not getting desired output in Creating a Multiclient Chat Server? - java

I am trying to create a multiclient chat sort of server in which we have multiple clients connecting to server and whatever message a client enters, it gets displayed to all the clients(including the client who sent the message). I am not getting this output, instead the message just echoes only on the sender client and no other client. Code is quite long, hence i am displaying snippets of whichever code i think will help you understand error. In case, it is not enough, just comment which part you require. Thanks in advance. I am stuck on this since about hour and half, so i appreciate whatever help i would get.
The Server Class
public class Multiserver {
ServerSocket serversocket;
Socket socket;
ArrayList<Socket> al = new ArrayList<Socket>();
DataInputStream dis;
DataOutputStream dos;
Multiserver() throws IOException
{
serversocket = new ServerSocket(1036);
System.out.println("Server started on port 1036");
while(true)
{
socket = serversocket.accept();
System.out.println(socket);
al.add(socket);
Mythread thread = new Mythread(socket, al);
thread.start();
}
}
Thread used in server class
public class Mythread extends Thread{
Socket socket;
ArrayList al;
DataInputStream dis;
DataOutputStream dos;
Mythread(Socket socket, ArrayList al)
{
this.socket = socket;
this.al = al;}
public void run()
{
try{
String data ="";
dis = new DataInputStream(socket.getInputStream());
data = dis.readUTF();
if(!data.equals("stop"))
{
broadcast(data);
}
else
{
dos = new DataOutputStream(socket.getOutputStream());
// data = dos.readUTF();
dos.writeUTF(data);
dos.flush();
//dos.close();
}
}
catch(Exception e){
System.out.println("Run "+e);
}
}
public void broadcast(String data)
{
try{
Iterator it = al.iterator();
while(it.hasNext())
{
Socket socket1 = (Socket)it.next();
dos = new DataOutputStream(socket1.getOutputStream());
dos.writeUTF(data);
dos.flush();
}
}
catch(Exception e){
System.out.println("Broadcast running "+ e);
}
}
}
The client class
public class Multiclient {
Socket socket;
DataInputStream dis;
DataOutputStream dos;
Multiclient() throws IOException
{
socket = new Socket("127.0.0.1", 1036);
System.out.println(socket);
Mythreadc my = new Mythreadc(socket);
my.start();
}
Thread used in client class
public class Mythreadc extends Thread{
DataInputStream dis;
DataOutputStream dos;
Socket socket;
Mythreadc(Socket socket)throws IOException
{
this.socket = socket;}
public void run()
{
BufferedReader br = null;
try{
br = new BufferedReader(new InputStreamReader (System.in));
dos = new DataOutputStream(socket.getOutputStream());
String data = "";
do{
data = br.readLine();
dos.writeUTF(data);
System.out.println(data);
dos.flush();
}
while(!data.equals("stop"));
}
catch(Exception e)
{
System.out.println("Client input "+e);
}
finally{
try{
br.close();
dis.close();
dos.close();
}
catch(Exception e)
{
System.out.println("Closing "+e);
}
}
}
}
I am sorry i have put on such a long code, almost all the program. But i feel it is necessary to understand where the problem lies.I have tried and i think it lies in the part where we display data written in the client's socket in the client thread class but i don't know what it is ???
#EDIT: Forgot to mention. The client stops when he sends the message "Stop"!

There are two problems with your code that are preventing the clients from displaying more than one message.
Problem one: Your client code never actually displays or prints out the messages it receives from the server. The line
dos = new DataOutputStream(socket.getOutputStream());
creates an OutputStream you can use to write data to the socket, i.e. send messages to the server. But you never use the socket's InputStream, which is what you need to do to read data from the socket, i.e. receive messages from the server. When you see a message printed out on the client, you're actually just seeing the result of
System.out.println(data);
which has your client print the message it just sent.
In order for the client to accept input from the user and read messages from the server at the same time, you should probably use two threads on the client. One thread can just be the client thread you already wrote, since it takes care of accepting input from the user. The other thread should look something like this:
public class ClientReaderThread extends Thread {
Socket socket;
ClientReaderThread(Socket socket) {
this.socket = socket;
}
public void run() {
try (BufferedReader serverReader = new BufferedReader(
new InputStreamReader(socket.getInputStream()))){
String fromServer = serverReader.readLine();;
while(fromServer != null) {
if (fromServer.equals("stop"))
break;
System.out.println(fromServer);
fromServer = serverReader.readLine();
}
} catch (IOException e) {
System.out.println("Client error! Got exception: " + e);
}
}
}
(Note that I use the try-with-resources statement to construct the reader, which takes care of closing it when the client stops).
Then in your main client class, start both threads with the same socket:
Multiclient() throws IOException
{
socket = new Socket("127.0.0.1", 1036);
System.out.println(socket);
Mythreadc my = new Mythreadc(socket);
ClientReaderThread reader = new ClientReaderThread(socket);
my.start();
reader.start();
}
Problem two: Your server only reads and echoes a single line from each client, because the socket thread that handles each client (Mythread) doesn't contain a loop. With your setup of creating a single thread per client, run() only gets called once per client, so that run() method needs to handle every message that client sends.
Here's how the run() method in the server's thread should look:
public void run() {
try (BufferedReader inStream = new BufferedReader(
new InputStreamReader(socket.getInputStream()))){
String data = inStream.readLine();
while(data != null) {
if(data.equals("stop"))
break;
broadcast(data);
data = inStream.readLine();
}
}
catch(Exception e){
System.out.println("Run exception "+e);
} finally {
al.remove(socket); //This is important to do
}
}
I made an additional important change here: at the end of the run() method, when either the client disconnected or an exception happened, the thread removes its socket from the ArrayList. This ensures that other server threads, which all reference the same ArrayList, don't try to broadcast to the socket of a client that has disconnected. If you neglect to do this, you'll get an exception when a client sends a message to the server after another client has disconnected.
Miscellaneous notes
As I mentioned in my comment, you should give al a type of ArrayList<Socket> inside the thread class, and use a for-each loop instead of an Iterator to iterate over it in broadcast().
I'm using BufferedReader instead of DataInputStream to read from the socket. That's because DataInputStream.readUTF() and writeUTF() are deprecated, and have been replaced with BufferedReader.readLine() and PrintWriter.println().
The streams like dis and dos don't need to be instance variables in your thread classes, since they are only ever used inside the run() method. They can be local variables inside run(), like I did with inStream in my new run() method.

I think you just missed passing the ArrayList of Sockets Users Currently Connected to The Server to the thread
and Instead of Posting your Server Class You have just posted Client Program 2 times anyway ,
Your ServerClass should be build in this way : -
As soon as ServerClass recieves the request from any client, Server Class should add the Socket into ArrayList and create New Thread and just pass both to the MyThread Class
Edit :
It seems you haven't written code for Displaying the data you will get from the server .
At Client Side for Sending the Message You can simple write that in Main Thread that is under Your Client Class's Main Mehtod
You actually needed Thread at client side not for sending the message but rather for Listening the Message from the server,
because you never known when anyone can send you the message but you will always know when you want to send message to anybody connected to this chat App
Now coming to the Coding Part :
Client Class
public class Multiclient {
Socket socket;
DataInputStream dis;
DataOutputStream dos;
Multiclient() throws IOException
{
socket = new Socket("127.0.0.1", 1036);
System.out.println(socket);
Mythreadc my = new Mythreadc(socket);
my.start();
/**
* Here write out the code for taking input from Standard Console
*/
BufferedReader br = null;
try{
br = new BufferedReader(new InputStreamReader (System.in));
dos = new DataOutputStream(socket.getOutputStream());
String data = "";
do{
data = br.readLine();
dos.writeUTF(data);
System.out.println(data);
dos.flush();
}
while(!data.equals("stop"));
}
catch(Exception e)
{
System.out.println("Client input "+e);
}
}
Client Thread
try{
String data ="";
dis = new DataInputStream(socket.getInputStream());
while(data.equalsIgnorCase("stop")){
data = dis.readUTF();
System.out.println("Server Message : "+data);
}
}
catch(Exception e){
System.out.println("Run "+e);
}
Client Thread is not complete but i think this information is sufficient enough .
Hope It help you out , Your problem do remind me of College Days :)

Related

Peer-to-peer chat not receiving/sending messages

I am trying to create peers that are connected to each other and are able to send/receive messages to everyone that they are connected to concurrently. They are all run on the same machine. Once connecting to a peer and acquiring a socket connection, I am starting two threads, one that is reading and one that is writing. However, readLine() blocks indefinitely and I am not sure where the problem exists. The peers successfully connect to each other, but the message exchange fails. Interrupting one peer causes a "null" message to be read from the other peers connected to it.
EDIT: Using autoflush = true in PrintWriter throws "ConnectionReset" exception to the other peers connected to the interrupted peer.
I have tried waiting for the reading thread to start before sending the message, getting the socket connection from either end of the peers, storing the input/output streams in lists stored as member variables and also just passing only the socket/all streams to each thread. Also tried different ways of reading, shown in comments in the reading thread.
class ConnectionListener extends Thread{
public void run(){
try {
while (!allPeersJoined()) {
Socket socket = null;
socket = peerServer.accept();
new PeerReader(socket).start();
new PeerWriter(socket).start();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
}
class PeerWriter extends Thread{
PrintWriter writer;
public PeerWriter(Socket socket){
try {
this.writer = new PrintWriter(socket.getOutputStream(), true);
}catch (IOException e){
e.printStackTrace();
}
}
#Override
public void run() {
writer.println("Hello");
}
}
class PeerReader extends Thread{
BufferedReader reader;
public PeerReader(Socket socket){
try {
this.reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}catch (IOException e){
e.printStackTrace();
}
}
#Override
public void run() {
String input = "";
System.out.println("Waiting to receive messages...");
try {
System.out.println(reader.readLine());
// while((input = reader.readLine()) != null){
// System.out.println(input);
// }
}catch (IOException e){
e.printStackTrace();
}
}
}
EDIT: Adding socket creation
Thread t = new ConnectionListener();
t.start();
// Connect to all peers
for (String peer : peers) {
new Socket("127.0.0.1", Integer.valueOf(peer));
}
You are creating multiple socket but then never use them.
Right now the ConnectionListener get your connection, send the bytes on the connected sockets, but the sockets never responds ... because you never told them to.
You should in the same way you did with ConnectionListener, create an object called
ClientConnection, that has its own writer and reader.

Server Socket reads Client message indefinitely in Java

In my simple Java Client-Server program, when sending a message to the server and reading it there, readInt() reads indefinitely, making the program stick there.
I made sure I was only sending and receiving an int, nothing else, as you can tell by the code (I also tried with and without appending \n to the message sent to see if it would end):
Relevant Client Code
Socket server = new Socket("127.0.0.1", 2424);
DataOutputStream outputStream = new DataOutputStream(server.getOutputStream());
DataInputStream inputStream = new DataInputStream(server.getInputStream());
outputStream.writeInt(Protocol.Message.HANDSHAKE);
outputStream.write('\n'); // I tried with and without this
outputStream.flush();
Relevant Server Code
ServerSocket socket = new ServerSocket(2424);
System.out.println("Listening on port 2424");
while (connected) {
Socket client = socket.accept();
System.out.println("SERVER: Going to read a message"); // This shows
int messageType = (new DataInputStream(client.getInputStream())).readInt();
System.out.println("SERVER: Received a message (" + messageType + ")"); // This does not
commands.execute(messageType);
}
The message that should be printed after readInt() is never seen. I thought it would since I was only sending an int and receiving an int (4 bytes), it's not like I was sending more data than expected.
How should I go about making the readInt() end? Do I have to send a null byte or something else?
EDIT: Actual Server code (using Threads).
ServerSocket socket = new ServerSocket(2424);
System.out.println("Listening on port 2424");
while (connected) {
Socket client = socket.accept();
Worker worker = new Worker(client);
worker.start();
}
Worker Thread
public class Worker extends Thread {
private final Socket client;
private final Commands commands;
private final DataOutputStream outputStream;
private final DataInputStream inputStream;
public Worker(Socket client) throws IOException {
System.out.println("SERVER: Handling client message");
this.client = client;
outputStream = new DataOutputStream(client.getOutputStream());
inputStream = new DataInputStream(client.getInputStream());
commands = new Commands();
commands.addCommand(Protocol.Message.HANDSHAKE, new HandshakeCommand());
//commands.addCommand(Protocol.Message.RECEIVE_FILE, new ReceiveFileCommand());
}
#Override
public void run() {
System.out.println("SERVER: Running thread for client message");
try {
int messageType = inputStream.readInt();
System.out.println("SERVER: Received a message (ID " + messageType + ")");
commands.execute(messageType);
} catch (IOException | UnknownCommandException ex) {
System.out.println(ex);
}
}
}
The reason it was never reading is because nothing was being sent, as xander said.
And it was my fault I didn't include the actual client code, just the server code and a minimized version of the client code.
I was trying to send the message after the while() loop in the client (it also waits for messages from the server).
The solution was to delegate the the client's listening part into another thread so it didn't block the main thread that needed to send the message to the server.

Java Socket client/server pair can only send one message at a time

A successful conversation can be carried out between the client and the server. However this is only if one message is sent between the client and server.
Example (Works):
Client: Hello
Server: helloo
Client: what time is it
Server: Let me get that for you
Example (Does not work):
Client: Hello
Server: helloo
Server: *How are you today*
Server: *test message*
Client: Yes
The messages between the asterisks do not appear on the client side untill the client sends 2 messages. From what I understand it seems to work like a net-message system where the number of messages sent by the server has to equal n+-1 the number of messages sent by the client, for all the messages to be shown.
Client Side Code:
try {
Socket client_socket= new Socket(hostname,port_number);
PrintWriter output = new PrintWriter(client_socket.getOutputStream(),true);
BufferedReader input = new BufferedReader(new InputStreamReader(client_socket.getInputStream()));
BufferedReader stdIn=new BufferedReader(new InputStreamReader(System.in));
String fromUser,fromServer;
while ((fromServer=input.readLine())!=null) {
System.out.println("Server: "+fromServer);
if (fromServer.equals("Quit")) {
break;
}
fromUser=stdIn.readLine();
if (fromUser!=null) {
System.out.println("Client: "+fromUser);
output.println(fromUser);
}
}
}
Server Side Code:
try {
ServerSocket server_socket=new ServerSocket(port_number);
Socket client_socket= server_socket.accept();
PrintWriter output = new PrintWriter(client_socket.getOutputStream(),true);
BufferedReader input = new BufferedReader(new InputStreamReader(client_socket.getInputStream()));
BufferedReader stdIn=new BufferedReader(new InputStreamReader(System.in));
output.println("Established");
String fromUser, fromServer;
while ((fromUser=input.readLine())!=null) {
System.out.println("Client: "+fromUser);
if (fromUser.equals("Quit")) {
break;
}
fromServer=stdIn.readLine();
if (fromServer!=null) {
System.out.println("Server: "+fromServer);
output.println(fromServer);
}
}
}
Looking at the code I can see why this would happen, its because the SOP after the While loop initialization stops the code waiting for 1 line of input, and then waits to send its own sentence, before receiving another. I tried putting these within the if statements, but this results in no communication at all.
I cant seem to figure out how to fix this.
If this requires threads, is there another way? (i'm not too familiar with threads)
Depending on the nature of your program, i would advise you to use more threads to handle messaging.
Lets start with the server:
If the server can have multiple clients, than it probably would be wise to distinguish every client with a thread, for example:
ServerSocket ss;
try {
ss = new ServerSocket(portIn);
while (true) {
Socket s = ss.accept();
// Option 1: runnable class
new Thread(new CustomRunnableClass(s)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
Or if you dont want your "session manager" to be a custom runnable class, you can replace the line new Thread(new CustomRunnableClass(s)).start(); with the following
new Thread(new Runnable() {
#Override
public void run() {
new SomeClass().runThisClass();
}
}
On the client side i would suggest that whatever class that listens to new messages from sockets will be distinguished by a new thread:
private void startListening() {
new Thread(new Runnable() {
#Override
public void run() {
for(;;) {
String msg = dis.readUTF();
System.out.println(" ----- Recieved New Message -----\n" + msg);
for (IMessageListener listener : listeners) {
try {
listener.onMessageRecieved(msg);
} catch (Exception e) {
}
}
}
}
}).start();
}
this way the client listens to any message received by the client and runs a method to handle them upon receiving, and is not hung in the meanwhile.
Hope this was helpful.
you need non-blocking sockets, the reader function should return intermediately if there is no data in the input buffer.
http://www.java2s.com/Tutorials/Java/Java_Network/0070__Java_Network_Non-Blocking_Socket.htm

Java socket keeps freezing

I'm trying to implement a simple server(java application) and client(android app), where the client sends a string about 10 times a second. Everything works fine for a minute or so, after which the server stops receiving messages from the client. Relevant code below.
ClientThread.java
public class ClientThread implements Runnable{
static Socket socket;
static String message = "";
InetAddress serverAddr;
BufferedOutputStream bos;
public ClientThread(String message){
ClientThread.message = message;
}
#Override
public void run() {
try{
serverAddr = InetAddress.getByName(SERVER_IP);
if(socket != null && socket.isConnected())socket.close();
socket = new Socket(serverAddr, SERVER_PORT);
bos = new BufferedOutputStream (socket.getOutputStream());
OutputStreamWriter osw = new OutputStreamWriter(bos, "US-ASCII");
osw.write(message);
osw.flush();
socket.shutdownOutput();
socket.close();
}catch (Exception e) {
}
}
}
ServerThread.java
public class ServerThread extends Thread{
private ServerSocket serverSocket;
static String clientSentence;
public ServerThread(int port) throws IOException, AWTException{
serverSocket = new ServerSocket(port);
}
public void run() {
while(true){
try{
Socket server = serverSocket.accept();
BufferedReader d = new BufferedReader(new InputStreamReader(server.getInputStream()));
clientSentence = d.readLine();
System.out.println(clientSentence);
server.close();
}catch(IOException e){
e.printStackTrace();
break;
}
}
}
}
ClientThread.java is called about 10 times a second using:
Thread clientThread = new Thread(new ClientThread(message));
clientThread.start();
ServerThread.java is initialized and started using:
t = new ServerThread(8888);
t.start();
Any thoughts on why this would freeze after running for a bit? The only way to fix it is to restart the server, after which the same problem happens again after a minute. I spent a lot of time researching this issue but was unable to find a solution.
EDIT: I figured out the server freezes at the clientSentence = d.readLine(); part. Any idea why?
60 connection per second, one minute running: 3600 connections per minute.
Closing a socket doesn't release immediately the associated file descriptor. You may run out of resource at OS layer.
Try to run netstat on server side to see the active, pending and closed connections.
You may read this post on SU.
Your thread never exits and you keep creating new ones. So you run out of something: thread space, sockets, FDs, ...
This is all wrong. Either your thread should loop or you should create a new one. Not both.
Also:
You should use a single connection, not a new one per message.
You are reading lines but to sending them, unless the data already contains a newline, which it shouldn't.

Using the same client socket to send multiple messages to server socket

There's a million examples on using Java sockets out there - and every one is the same!
Every one shows a client socket being created, some text being sent, and the socket closed.
I am writing some test code. I want my client to loop round and send quite a few messages. It seems silly to close the client socket each time and re-create, so I thought I would just create one client socket, loop round and send data on the same socket. The thing is though - my server socket does not print out what it has received until the last message has been sent by the client and the client socket closed.
Server:
Socket sock;
ClientConnection client;
ServerSocket ss = new ServerSocket(portNumber);
ss.setSoTimeout(0); // 0=infinite
while (true) {
sock = ss.accept();
client = new ClientConnection(sock);
new Thread(client).start();
// ClientConnection reads from sock, prints, and closes sock
}
ClientConnection (a separate class on the Server side):
public class ClientConnection implements Runnable
{
private Socket m_socket;
private BufferedReader m_in = null;
public ClientConnection(Socket socket)
{
m_socket = socket;
try {
InputStream inStream = socket.getInputStream();
m_in = new BufferedReader(new InputStreamReader(inStream));
}
catch (IOException ioe) {
ioe.printStackTrace();
}
}
public String getMessage()
{
String line = null;
StringBuffer completeMessage = new StringBuffer();
try {
while ((line = m_in.readLine()) != null)
{
completeMessage.append(line);
}
}
catch (IOException ioe) {
ioe.printStackTrace();
return "";
}
return completeMessage.toString();
}
public void run()
{
try {
String message = getMessage();
System.out.println("Received: " +message);
}
finally
{
try {
m_socket.close();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}
Client:
socket = new java.net.Socket(m_destination, m_portNumber);
outputStream = socket.getOutputStream();
printStream = new java.io.PrintStream(outputStream);
while (more-stuff-to-send)
{
printStream.print(text);
printStream.print("\n");
printStream.flush();
}
prinStream.close();
socket.close();
ClientConnection is created by the server when I start the client, but it does not print what has been sent until the client is done sending.
I feel like I'm missing the point somewhere along the line. Chat examples are quite common, so if I had a chat client then every message it wanted to send to a chat server it would create a client socket, send the message, and close the socket? Just doesn't seem right somehow.
Thank you.
client = new ClientConnection(sock);
You are passing the socket in constructor.
so you shouldn't do:
socket = new java.net.Socket(m_destination, m_portNumber);
just cache that vatiable from contructor as : this.sock = sock;
getting the reader and the writer is ok, also the server is ok.
I would use a Vector to be synchromized queue for sending messages, and the while (more-stuff-to-send) loop would check the queue and id empty than sleep, if has something to send, than pop the first and sent it while he must do stuff, or socket is closed my the client.

Categories

Resources