Chat: Sending message to all clients on a server - java

I have a server-client application set. (HOMEWORK)
So far I have figured out how to have multiple clients connect to the server and have the server aggregate the messages the clients send, as well as having the server send the client's message back to the client and displaying it in the chat pane.
My issue is trying to send a message to multiple clients. I am only allowed to use ServerSocket and Socket libraries.
Say I have 2 clients connected to the server. One client sends a message, the message is displayed in the client's chat. The second client sends a message, the first client does NOT receive it, and the second client's chat window displays the first client's message.
Essentially the server is sending the most recent message that the respective client has not displayed in the chatbox, and I have no idea why or how.
Code for server-to-client communication :
Class CommunicationThread extends Thread {
//Vector containing all client sockets currently connected
//Held offsite, here for clarity
public Vector<Socket> socketVector;
public CommunicationThread (Socket clientSoc, Server ec3, Vector<Socket>socketVectorg)
{
//add new socket to vector, start thread
clientSocket = clientSoc;
socketVectorg.add(clientSocket);
this.socketVector = socketVectorg;
gui = ec3;
}
public void run()
{
System.out.println ("New Communication Thread Started");
try {
//Client's chat box (output)
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),
true);
//Input line from client
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println("Server: " + inputLine);
gui.history.insert(inputLine + "\n", 0);
//*************HERE IS MY ISSUE*******************
for(Socket s : socketVector){
out = new PrintWriter(s.getOutputStream(),
true);
out.println(inputLine);
}
if (inputLine.equals("Bye."))
break;
if (inputLine.equals("End Server."))
gui.serverContinue = false;
}
out.close();
in.close();
clientSocket.close();
}
catch (IOException e)
{
System.err.println("Problem with Communication Server");
//System.exit(1);
}
}
}
I know I am overwriting "out" but I don't think that is my issue so it is in my code while I am testing.
My issue is marked in the code above. The vector accurately stores the socket ID, and since I am creating a new PrinterWriter based on the vector, I would only assume that it would get the output field of the respective client, but it does not.
My intuition is that it is a problem with threading or closing the output, but I honestly don't know.
Any recommendations are appreciated.

Your problem it seems to me is that you want to do the input and output work on the client socket all in the same place, and there's no need for that. The client socket's output stream can be written to in the GUI thread, and all in one place. You can keep a collection of the output streams if need be and when you want to reply to all, iterate through the collection (probably a HashMap<String, OutpuStream> where the String is some client identifier) and send the messages.

Related

Socket client not receiving messages from server only when server performs a loop

I am trying to make a server (written in Python) and a client (written in Java) to communicate. The server code is the following:
import socket # Import socket module
connection=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connection.bind(('',12800))
connection.listen(5)
connection_with_client, info_connection = connection.accept()
msg=b""
while(msg!=b"stop"):
print("Entering loop")
msg = connection_with_client.recv(1024)
connection_with_client.send(b"This is a message")
print("Sent")
connection_with_client.close()
connection.close()
The client code is:
try {
socket = new Socket(InetAddress.getLocalHost(),12800);
PrintWriter out = new PrintWriter(socket.getOutputStream());
out.print("stop");
out.flush();
System.out.println("Sent");
in = new BufferedReader (new InputStreamReader (socket.getInputStream()));
String message_from_server = in.readLine();
System.out.println("Received message : " + message_from_server);
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
The strange thing is: when the client sends the message "stop", everything goes fine, message from server is received by the client. Now, when the client sends another message than "stop", the server tells it has sent the message, and enters the loop a second time, however the client never receives the message and gets stuck at the in.readLine() instruction.
I really don't get why as the first passage in the loop should have the same effects in both situations... Any help welcome!
On client side you are using readLine. Obviously, this reads the line, but how it detects where the line ends? The answer is:
you server should append line ending to all messages you send to client.
Try append b'\r\n' or whatever are lineendings on your OS. As far as readLine is called on client side, you should append line ending of a client, not server OS.
For Windows it is b'\r\n'
For Linux b'\n'

How would i change this code to allow more than one user input message to be sent between the client and server

I've just started with both java and networking with servers and clients. Although i understand the basics of whats going on, i was struggling to put it all together and do what i wanted to do in the title.
I was able to make this to send a message to the server, however i was wondering how i'd turn the message into a input string from the user, and also how id send multiple messages between the client and server
thanks
SERVER
import java.io.*;
import java.net.*;
public class Server {
//Main Method:- called when running the class file.
public static void main(String[] args){
//Portnumber:- number of the port we wish to connect on.
int portNumber = 15882;
try{
//Setup the socket for communication and accept incoming communication
ServerSocket serverSoc = new ServerSocket(portNumber);
Socket soc = serverSoc.accept();
//Catch the incoming data in a data stream, read a line and output it to the console
DataInputStream dataIn = new DataInputStream(soc.getInputStream());
System.out.println("--> " + dataIn.readUTF());
//Remember to close the socket once we have finished with it.
soc.close();
}
catch (Exception except){
//Exception thrown (except) when something went wrong, pushing message to the console
System.out.println("Error --> " + except.getMessage());
}
}}
CLIENT
import java.io.*;
import java.net.*;
public class Client {
//Main Method:- called when running the class file.
public static void main(String[] args){
//Portnumber:- number of the port we wish to connect on.
int portNumber = 15882;
//ServerIP:- IP address of the server.
String serverIP = "localhost";
try{
//Create a new socket for communication
Socket soc = new Socket(serverIP,portNumber);
//Create the outputstream to send data through
DataOutputStream dataOut = new DataOutputStream(soc.getOutputStream());
//Write message to output stream and send through socket
dataOut.writeUTF("Hello other world!");
dataOut.flush();
//close the data stream and socket
dataOut.close();
soc.close();
}
catch (Exception except){
//Exception thrown (except) when something went wrong, pushing message to the console
System.out.println("Error --> " + except.getMessage());
}
}}
There are some "problems" with your code.
You should only close the ServerSocket if you are done.
You should handle the newly connected client inside a thread to allow multiple clients to simultaniously "send messages".
1.
you could easily wrap your code inside an while loop.
boolean someCondition = true;
try{
//Setup the socket for communication and accept incoming communication
ServerSocket serverSoc = new ServerSocket(portNumber);
// repeat the whole process over and over again.
while(someCondition) {
Socket soc = serverSoc.accept();
//Catch the incoming data in a data stream, read a line and output it to the console
DataInputStream dataIn = new DataInputStream(soc.getInputStream());
System.out.println("--> " + dataIn.readUTF());
}
//Remember to close the socket once we have finished with it.
soc.close();
}
Now your programm should continue to accept clients. But only one at a time. You can now terminate the Server by stopping the programm or by changing the someCondition to false and accepting the next client.
A bit more advanced would be, to shutdown the ServerSocket to stop the programm and catching the exception inside the while loop.
2.
To allow multiple clients to be handled simultaniously, you should pack the handle part into another Thread.
private ExecutorService threadPool = Executors.newCachedThreadPool();
boolean someCondition = true;
try{
//Setup the socket for communication and accept incoming communication
ServerSocket serverSoc = new ServerSocket(portNumber);
// repeat the whole process over and over again.
while(someCondition) {
Socket soc = serverSoc.accept();
//Catch the incoming data in a data stream, read a line and output it to the console in a new Thread.
threadPool.submit(() -> {
DataInputStream dataIn = new
DataInputStream(soc.getInputStream());
System.out.println("--> " + dataIn.readUTF());
}
}
//Remember to close the socket once we have finished with it.
soc.close();
}
The part inside the threadPool.submit block could be specified as an custom instance of the Runnable interface of as an method, to call it using method reference.
I assumed you are knowing about ThreadPools. They have multiple advantages over Threads
This should get you going for any number of clients.
Note: This is not good designed, but it is for demonstrational porpurses only.

putting socket connection to dormant state while waiting for data from server

I have a client socket connected to the server socket, the server will send data to the client from time to time while its connected. currently my client uses a while loop to keep receiving data from the server even the server is not sending anything.
my question is, is there any more efficient way to listen for input?
i am thinking maybe create a thread for the socket connection, and put it to sleep when there is no incoming data, and sends an interrupt when there is data coming in. would that work? if putting the thread to sleep, would it break the socket connection?
i cannot modify the server socket and it doesnt initiate a connection.
import java.io.*;
import java.net.Socket;
public class core_socket {
public static void main(String[] args) {
String host = ("192.168.100.206");
int port = 4025;
try {
Socket socket = new Socket(host, port);
System.out.println("created socket\n");
OutputStream os = socket.getOutputStream();
boolean autoflush = true;
PrintWriter out = new PrintWriter(socket.getOutputStream(), autoflush);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// read the response
boolean loop = true;
StringBuilder sb = new StringBuilder(8096);
while (loop) {
if (in.ready()) {
int i = 0;
while (i != -1) {
i = in.read();
sb.append((char) i);
}
loop = false;
}
}
// display the response to the out console
System.out.println(sb.toString());
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
See multi-user chat application example at http://cs.lmu.edu/~ray/notes/javanetexamples/ - basically, you should consider spawning off a new worker thread for each incoming connection and then go back to listen for any new incoming requests.
A long time ago I wrote one of the first application servers (say in 1997 when most people didn't know what an app server is) - it was deployed at one of the largest higher-ed institutions and processed couple million requests per day during peak times - that's not the institution in the link by the way. The reason I mention this is... multi-threading gives you a tremendous scalability with very little effort - even if scalability is not what you are looking for, worker thread model is still a good practice.
Maybe what you want is to use asynchronous sockets. Basically, it spins off another thread that's job is to listen for any data on the socket. Once data does come in, a "callback" method is called, which can then begin to process your data.
I've never done sockets in Java before though, just C#, so I'm not sure how it compares, but the concept should remain the same.

Growl forwarding to Java server

I have a java server which is using TCP and sockets to connect to an Android application (the client) and sends strings (currently taken in from a scanner object) which are then displayed as notifications by the client.
heres the Server code without all the imports.
public class Server {
// define our Main method
public static void main(String[] args) throws IOException {
// set up our Server Socket, set to null for the moment.
ServerSocket serverSocket = null;
boolean isConnected = false;
// Lets try and instantiate our server and define a port number .
try {
serverSocket = new ServerSocket(6789);
isConnected = true;
System.out.println("*** I am the Server ***\n");
// make sure to always catch any exceptions that may occur.
} catch (IOException e) {
// always print error to "System.err"
System.err.println("Could not listen on port: 6789.");
System.exit(1);
}
// We always want to check for connection from Clients, so lets define
// a for ever loop.
for (;;) {
// define a local client socket
Socket clientSocket = null;
// lets see if there are any connections and if so, accept it.
try {
clientSocket = serverSocket.accept();
// don't forget to catch your exceptions
} catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
// Prepare the input & output streams via the client socket.
// fancy way of saying we want to be able to read and write data to
// the client socket that is connected.
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
PrintWriter outToClient = new PrintWriter(clientSocket.getOutputStream(),
true);
while (isConnected) {
// read a sentence from client
String hiFromClient = inFromClient.readLine();
// Set up the logging system and timestamp and log message.
Calendar currentDate = Calendar.getInstance();
SimpleDateFormat formatter=
new SimpleDateFormat("yyyy/MMM/dd HH:mm:ss");
String dateNow = formatter.format(currentDate.getTime());
try{
// Create file
File fstream = new File("log.txt");
FileWriter out = new FileWriter(fstream);
out.write(hiFromClient + " " + dateNow);
//Close the output stream
out.close();
} catch (Exception e){//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
// Print the client sentence to the screen
System.out.println("The Client said: "+hiFromClient);
// Reply to the client
Scanner scanner = new Scanner(System.in);
String sentence = scanner.nextLine();
outToClient.println(sentence );
System.out.println("The Server said: " + sentence);
}
// always remember to close all connections.
inFromClient.close(); // the reader
outToClient.close(); // the writer
clientSocket.close(); // and the client socket
}
}}
Growl uses port 23053 for notification forwarding. What i am hoping to do is to listen in on 23053 and send anything in from that as a string to the client connected at 6789. Sadly Growl binds the port number so a new Socket connection cant be made.
Any one have any ideas on how i could get notifications from the port number growl uses or even just use growl as the server for the client itself (the client's code is very similar to the servers by the way just using Socket instead of ServerSocket)
Any help on this would be greatly appreciated, its wrecking my brain
All the best,
Patrick.
There is a round-about way you could do it. If you are desperate, read on:
Growl can forward any notifications it receives to another machine running Growl (configured on the Network tab). Growl uses the GNTP protocol (a TCP-based protocol: http://www.growlforwindows.com/gfw/help/gntp.aspx) to forward the messages. The trick is that that 'other machine running Growl' doesnt have to really be another machine OR running Growl per se, it just needs to appear to Growl that it is. Growl (on the Mac, which is what I assume you are using) will automatically detect any other machines on the network running Growl (using Bonjour and looking for the _gntp._tcp service name), so if your server advertises itself as supporting the GNTP protocol, Growl should show it in the list of available destinations. (Growl for Windows also lets you manually add a hostname/port to forward to, but I dont believe the Mac version currently allows that).
So then you could configure Growl to forward notifications to your server using its already-built-in capabilities. You would have to implement code in your server to receive the GNTP packets (the format is very similar to HTTP headers) and parse them. Then you could forward the notifications using your current server code.
Still with me? I did say it was round-about, but it is not only technically possible, but I have built a Growl-impersonating daemon before so that I could have notifications forwarded from Growl to my custom code. Not suggesting it as the best idea, but just an alternative since you asked.

buffered reader not receiving data from socket

I am writing a client application that will receive a continuous flow of data through tcp/ip. The problem I'm having is that the buffered reader object isn't receiving any data and is hanging at the readline method.
The way the server works is that you connect to it, and then send authentication information in order to receive data. The gist of my code is below
socket = new Socket(strHost, port);
authenticate();
inStream = new BufferedReader(new InputStreamReader(socket.getInputStream()));
process(inStream);
authenticate()
{
PrintWriter pwriter = new PrintWriter(socket.getOutputStream(), true);
pwriter.println(authString);
}
process(BufferedReader bufferedReader)
{
while((line = bufferedReader.readLine()) != null)
dostuff
}
I created a sample server application that sends data the way (I think) the server is sending data and it connects, and receives and processes the data fine. I can connect to the server fine in my application. I can also telnet to the server and write the authentication string and receive a flood of data using telnet. However my application just hangs at readLine with the server and I'm out of idea's why.
The data coming in (through telnet atleast) looks like a continuous stream of the following:
data;data;data;data;data
data;data;data;data;data
Why is my app hanging at readline, am I not outputting the authentication line correctly? I'm not receiving any errors...
EDIT
My sample server code (which is working correctly)...again this is only mimicking the way I think the real server is running but I can connect to both in my application just not receive data from the real server.
public static void main(String[] args) throws IOException
{
ServerSocket serverSocket = null;
try
{
serverSocket = new ServerSocket(1987);
}
catch (IOException e)
{
System.out.println("Couldn't listen on port: 1987");
System.exit(-1);
}
Socket clientSocket = null;
try
{
clientSocket = serverSocket.accept();
}
catch (IOException e) {
System.out.println("Accept failed: 1987");
System.exit(-1);
}
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String something;
while ((something = in.readLine()) != null)
{
while(true)
{
out.println(message);
}
}
out.close();
in.close();
clientSocket.close();
serverSocket.close();
}
Firstly you should call BufferedReader.ready() before calling readLine(), as the ready() will tell you if it's ok to read.
PrintWriter doesn't throw I/O Exception so the write may have failed without your knowledge which is why there is nothing to read. Use PrintWriter.checkError() to see if anything as gone wrong during the write.
You ought to set up the input and output streams on the Socket at the same time before you write anything down the pipe. If your reader is not ready when the other end tries to write you will get a broken pipe in the server and it won't send any more data. Telnet sets up read and write before you have written or read anything.
You can make use of Wireshark to tell if the server is actually sending data.
BufferdReader.readLine() reads lines, i.e. sequences of characters ended with \r or \r\n. I guess that your server writes its output into one single line. Your telnet output proves this assumption. Just use PrintWriter.println() at server side.
this work with me
with socket without flush
void start_listen()
{
String result1="";
char[] incoming = new char[1024];
while (!s.isClosed())
{
try {
int lenght = input.read(incoming);
result1 = String.copyValueOf(incoming,0,lenght);
}
catch (IOException e)
{
e.printStackTrace();
}
Log.d("ddddddddddd",result1);
}

Categories