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

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.

Related

How to stop Java Socket client keeps sending 'null' data?

I created 2 Java programs with sockets in it. I want the client to send continuous data to the server. But after the message sent to the server, the client keeps sending 'null' value to the server (it happens when I close the socket in client program).
Here is my codes:
import ...
public class MainClient {
private Socket serverSock;
private PrintStream clientOutput;
public static void main(String[] args) {
MainClient client = new MainClient();
client.runClient();
}
public void runClient() {
try {
serverSock = new Socket("127.0.0.1",8282);
clientOutput = new PrintStream(serverSock.getOutputStream());
clientOutput.println("Hello, I'm Connected.");
for (int i=0;i<5;i++) {
clientOutput.println(i + "");
clientOutput.flush();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
// try {
// serverSock.close(); It will keeps sending 'null' data to the server if I use this line.
// } catch (IOException e) {
// e.printStackTrace();
// }
}
}
}
The Server Side:
public class MainServer {
private ServerSocket serverSocket;
private int listenPort = 8282;
private InputStream inps;
private Socket clientSocket;
private BufferedReader clientInput;
private MainServer() {
String clientMsg = "";
try {
serverSocket = new ServerSocket(listenPort);
System.out.println("Server is Listening on " + listenPort);
clientSocket = serverSocket.accept();
clientInput = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while(clientSocket.isConnected()) {
clientMsg = clientInput.readLine();
System.out.println("Client : " + clientMsg);
}
}catch(IOException ex) {
ex.printStackTrace();
}finally {
try {
clientSocket.close();
} catch (IOException e) {}
}
}
public static void main(String[] args) {
new MainServer();
}
}
I tried to close the OutputStream on the Client side with clientOutput.close(); but it sends nulls to the server after it sends the 0-4 loop.
To make it stop and avoid the client sends null data, i should not insert the serverSock.close(); on the Client, but it will returns SocketException. I wanted the client to send 'Closed' message after its done.
Summary, the output on the server is:
Client: 0
Client: 1
Client: 2
Client: 3
Client: 4
Client: null
Client: null
//And so on..
I think there is something missing on the Client Program, i guess?
Thank you for the help :)
As the comment noted, the client is not sending a null value.
The isConnected() method does not do what you think it does, namely it does not tell you if the socket is currently "connected" to its peer, at least in the way you think it should. isConnected() becomes true as soon as the socket transitions into the connected state, and stays true thereafter, even after the socket is shutdown. See this discussion and others on stackoverflow.
The correct way to determine if the peer has shutdown the connection is to attempt to read from the socket and then examine the result for evidence of closure. Please read the Javadocs for the method you are using, they will tell you what the various return values mean. For the BufferedReader.readLine() method, it says:
Returns:
A String containing the contents of the line, not including
any line-termination characters, or null if the end of the stream has
been reached
Throws:
IOException - If an I/O error occurs
Thus you need to check for a null return value to detect a normal socket closure, and if you receive an IOException that indicates some kind of network anomaly.
Your MainClient() have no problem.
clientSocket.isConnected() function in MainServer() always check the status of the client and which results an infinite loop, so after the message 'client:4', clientInput.readLine() should return 'null'.
So instead of checking the client socket is connected or not you can check the client socket is closed or not using function 'clientSocket.isClosed()'.
replace the while loop in MainServer() with below code,
while(!clientSocket.isClosed()) {
clientMsg = clientInput.readLine();
System.out.println("Client : " + clientMsg);
if(clientMsg.equals("Closed")){
clientSocket.close();
// serverSocket.close();
}
}
this will help you to close the client socket at the time of receiving 'Closed' message from server and this avoid the infinite execution of while loop as well as null statement printing.
The code "serverSocket.close()" help you to close the server socket and you can use this at 'MainServer()' if you need to stop the port listening.
typically the code should be something similar
private MainServer() {
String clientMsg = "";
try {
serverSocket = new ServerSocket(listenPort);
System.out.println("Server is Listening on " + listenPort);
clientSocket = serverSocket.accept();
clientInput = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while ((clientMsg = clientInput.readLine()) != null) {
if(isTerminationString(clientMsg)) {
break;
}
System.out.println("Client : " + clientMsg);
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
}
}
}
boolean isTerminationString(String msg) {
return msg.equals("DONE!");
}
where in isTerminationString you check if the msg is a termination msg, the communication protocol should be shared between the client and the server . i gave the example of sending
a DONE message, but it could more complex than that .
as closing the close method on the socket does not guarantee that the socket on the other part gets closed as well, using the isClosed method might not be effective and results in the same problem you have .

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.

TCP IP Client receives no input but packet sent from server

I have a java client program that sends a command to server and server sends back an acknowledgement and a response string.
My client program gets the input stream length from client socket as
0. But, I used wireshark to investigate. Wireshark logs show that the server has sent back a response to my ip. Somehow, my client is unable
to read it.
My Client
public class Client {
private static final String SERVER_ADDRESS = "192.168.64.79";
private static final int TCP_SERVER_PORT = 6669;
public void connect(String command) {
BufferedReader in;
try {
// Socket skt = new Socket("50.128.128.254", 6669);//ip,port
Socket clientSocket = new Socket(SERVER_ADDRESS, TCP_SERVER_PORT);// ip,port
System.out.println(" client Socket created ..Enter command : ");
PrintWriter outToServer = new PrintWriter(clientSocket.getOutputStream(), true);
String ToServer = command;
outToServer.println(ToServer);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
System.out.print("Received string : length "+clientSocket.getInputStream().available()+"\n response:");
// while (!in.ready()) {
// }
System.out.println(in.readLine()); // Read one line and output it
// System.out.print("'\n");
in.close();
clientSocket.close();
System.out.print("connection closed");
} catch (Exception e) {
System.out.print("Whoops! It didn't work!\n");
e.printStackTrace();
}
}
}
WireShark results:
9bytes of data sent from server to my client
Client output
Java client receives inputstream length 0

No response from second client socket

I am working with Java sockets. I have a server socket and two client sockets. My problem is, that the first client socket submits its message to my server socket, and the message from the second client socket is not arriving at the server socket. That means, that for the first client socket the while loop is interrupted after a succesful message, and the second client ends in an infinite while loop. If I test each client socket seperately in a test class, each client socket is submitting its message correctly to my server socket. By watching TCPView I noticed, that the client socket does not respond, as long as my port is used.
I read, that the second client socket should still respond its message, even if the port was used. In my case, the second client socket should always respond about a second after the first one. But I can't get them to work one after another.
So, here is my code for the method, which is waiting for client messages:
public void listenToSocket()
{
serverSocket = null;
thread = null;
SocketAddress adress = new InetSocketAddress(CommunicationValues.SOCKET_PORT);
try {
serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(adress);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
System.exit(0);
}
while(true){
try
{
Socket clientSocket = serverSocket.accept();
thread = new SocketMessageThread(clientSocket);
thread.start();
} catch (IOException e) {
System.out.println("MyServerSocket caught an error: \n" + e.getMessage());
e.printStackTrace();
}
}
}
This method is called in a thread. The structure looks like this:
SocketListenerThread calls the method listenToSocket() from class SocketListener
listenToSocket() is described above
The SocketMessageThread is handling the message output of the client socket in its run()-method.
EDIT
Here is the code of my SocketMessageThread:
public class SocketMessageThread extends Thread{
private Socket clientSocket;
private static int nameCounter = 0;
public SocketMessageThread(Socket clientSocket) {
this.clientSocket = clientSocket;
this.setDaemon(true);
this.setName("SocketMessageThread" + (nameCounter++));
}
public void run() {
try (
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));)
{
while (in.ready())
{
String inLine = in.readLine();
CommunicationValues.MESSAGE_MEMORIZER = inLine;
}
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}}
EDIT 2
Both clients only communicate with one particular message. E.g. when a client is started up, it mentioned, that the startup was successful with a single message. There are no repeating messages coming from the client sockets until the server sockets catches them. So if the server socket doesn't catch that one message, it's gone, and it won't be sent again by the client socket.
while (in.ready())
{
// ...
}
Classic misuse of ready(). Exchange all this for:
String inLine;
while ((inLine = in.readLine()) != null)
{
CommunicationValues.MESSAGE_MEMORIZER = inLine;
}
Presumably there is more code that you haven't shown us: otherwise all this will do is memorize the last line sent.

Not getting desired output in Creating a Multiclient Chat Server?

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 :)

Categories

Resources