How can I subscribe to new socket messages in Java - java

I was making a simple client which connected to another server via Java Sockets and would await messages from that server and modify a video game it is running.
Socket socket = new Socket(server, 6667);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream( )));
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream( )));
String line = null;
while ((line = reader.readLine( )) != null) {
System.out.println(line);
}
Currently the while loop occupies the entire main thread and a way to fix that would be to put this process on a separate thread. Best case scenario I would like to create a listener that gets pinged whenever the thread receives a new message and sends it off to interact with the main thread.
I was wondering whether there exists a built in layer for this kind of process in java sockets (like pubsub or onMessage) because it feels like a very popular use case. Please let me know if I've missed something like this in my search, I apologize for my ignorance and thank you in advance.
Edit:
TLDR:
I have a main thread which is being occupied by a game and I would like to read incoming messages from a server, is there any built in way to do it besides employing listeners the manual way?

Related

Buffered Reader for a socket is never ready

Just to be completely transparent, this is for an assignment.
There is more to do, but at the moment I'm just trying to get the following:
Node A reads in from a text file
Node A sends text file (minus the first line) to Node B using a socket
Node B read in from said socket, and prints it out to the console
However, right now, it seems that either the information isn't being sent, or it's not being read correctly by Node B.
In my main class, I set up the nodes like this:
NodeA nodeA = new NodeA();
NodeB nodeB = new NodeB();
new Thread(nodeA).start();
new Thread(nodeB).start();
In node A, I do this:
//Open a socket for talking with NodeB
Socket mySocket = new Socket(InetAddress.getLocalHost(), portNum);
//Set up the socket's output
PrintWriter out = new PrintWriter(mySocket.getOutputStream(), true);
//Loop through the lines of the confA file, writing them to the socket
String line = bufferedReader.readLine();
while (line != null)
{
//Write the line to the socket, get the next line
out.println(line); //updated to println, this flushes and fixes another problem
out.flush();
line = bufferedReader.readLine();
}
//Close the socket
mySocket.close();
Note that Node A's loop works fine. It doesn't loop forever and does go through the intended lines of text when I tested with print statements.
Then, on Node B's end: Updated to show current Node B code
//Open the socket
ServerSocket mySocket = new ServerSocket(portNum);
Socket connectionSocket = mySocket.accept();
//Set up a reader on the socket to get what's coming from it
BufferedReader in = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
String line = in.readLine(); //hang occurs here
while(line != null) {
System.out.println(line);
line = in.readLine();;
}
However, in.ready() is never true. I've tried waiting around for that to happen using a while loop but it never occurs.
I'm really not sure why. I have no idea if I set up the socket correctly, if I set up the server correctly, if I am listening correctly, etc.
I just figured that making B into a server which is listening for A made the most sense. I hope that's right. It looks similar to what I saw some other examples on SO did.
Thank you for any and all help. I'm extremely unfamiliar with sockets, ports, listening and otherwise, so forgive me if I don't understand your suggestions at first. I'll do my best to understand it as I go.
I refrained from adding the whole of the code to hopefully make it more readable and clear where the issue might be, but if you need more information just feel free to ask and I'll do my best to provide it.
The server must first get from the ServerSocket the Socket to the client.
connectionSocket = mySocket.accept();
The server thread will be sleep till a client causes it to accept the connectionSocket.
Then you can read from the connectionSocket. ready not being needed.
As this is an assignment, I leave the rest to you.
By the way a typical server would do:
for (;;) {
Socket socket = serverSocket.accept();
... pass the socket to a thread from a pool of threads
}
I think the problem is that ready just means that if you call a read, it won't block. You can see the code that gets executed if you look up the function on grepcode:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/java/io/BufferedReader.java#BufferedReader.ready%28%29
A ready thread just means it's not going to block, which is useful when you want to ensure that your thread isn't going to get tied up, but doesn't really tell you if you have buffer or not.
What you want to do is perform the readline, as a blocking call, until the data is consumed. If you don't want this blocking your current thread, then spin off a new consumer thread specific for this reading that can block.
Also, make sure that you're ending your send communication with either a closed socket or flush to indicate to the consuming stream when it is complete. And you only need to socket accept once per open/close session.

java - continuous data sending through Socket

I'm writing a Java client/server application. It should allow clients to send text data to the server. This kind of communication should be repeatable many times using the same connection.
I write it like this:
// On a server:
ServerSocket serverSocket = new ServerSocket(port);
Socket socket = serverSocket.accept();
socket.setKeepAlive(true);
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
if (reader.ready()) {
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
// do something with line
}
}
// On a client:
Socket socket = new Socket(host, port);
socket.setKeepAlive(true);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("Some data from client to server");
writer.flush();
The problem is: I can't read on a server before I close OutputStream on a client. Or I can't open OutputStream on a client again, if it was already closed. How can I do continuous sending and reading of data?
You need two threads at both ends, one for reading data and other one for writing data.
The problem is: I can't read on a server before I close OutputStream on a client.
Yes you can. You just can't get to the case where readLine() returns null. It isn't the same thing.
Or I can't open OutputStream on a client again, if it was already closed.
Of course not. You have to create a new Socket.
How can I do continuous sending and receiving of data?
I don't understand the question. The code you posted doesn't attempt that.
If your goal is to send many mesages over the same socket connection, these messages will have to be delimited by an application-level protocol. In other words, you won't be able to rely on any system calls like reader.ready() or reader.readLine() == null to detect the end of the message on te server.
One way to achieve this is to begin each message with its length in characters. The server will then read exactly that number of charecters, and then stop and wait for a new message. Another is to define a special character sequence which concludes each message. The server will react to reading that particular sequence by ending the reading of the current message and returning to the "wait for new message" state. You must ensure that this sequence never appears in the message itself.

I Can't Send objects over sockets in Java

I have this problem, and I can't figure it out whats is wrong. I have searched on all over the internet, but without success.
So, I have to send an object over sockets in Java, and I can't figure out how to do it. I tried so many ways. I serialized the object, I tried to write the object directly. But nothing seems to work.
The detail is that I have a chat running in parallel. And sometimes when i open an ObjectOutputStream, or ObjectInputStream, I get busted in a deadlock. And I guess you guys could help me.
Its a hangman game where the clients connects to the server, and the server should send a random word, which is a object, to clients.
Server:
try{
socketConexao = socketRecepcao.accept();
toClient = new DataOutputStream(socketConexao.getOutputStream());
fromClient = new BufferedReader(new InputStreamReader(socketConexao.getInputStream()));
//starts the chat
Thread chat = new Thread(this);
chat.start();
}catch(IOException e){}
//i dont really know how to send the object
try{
byte[] bytes = serialize(palavraSorteada);
toClient.write(bytes);
} catch (IOException e){
e.printStackTrace();
}
Client:
socketCliente = new Socket(ip, port);
toServer = new DataOutputStream(socketCliente.getOutputStream());
fromServer = new BufferedReader(new InputStreamReader(socketCliente.getInputStream()));
// starts the chat
Thread chat = new Thread(this);
chat.start();
}catch(IOException e){System.exit (0);}
// and dont really know how to receive the object
try{
ObjectInputStream os = new ObjectInputStream(socket.getInputStream());
palavraSorteada = (Palavra) os.readObject();
os.close();
}catch(Exception e){
e.printStackTrace();
}
It should be fairly obvious what wrong here (from your description): You use one communication channel to send two different kinds of data. Since the receiving end can not predict what its going to receive you need to add information what comming next, so the receiving end knows what to do.
And probably noone is going to the trouble to figure out what your code fragments are really doing, reduce the fluff to what you want to ask about or even better make a one class copy&pasteable runnable example (as short as possible) that demonstrates the issue.
In Server, split class Server in Server (accepts connections) and ServerConnection (separate thread). Place variables toClient and fromClient into ServerConnection. Now you spoil that variables when new client connects.
In Client, no need to start new Thread.

Expanding my Java program to send a alert message to other computers

I've written a java intake program that send an PDF-formatted intake to a shared folder so that other people in the network can read it. However, there is not a way for the other people to know that an intake was sent unless someone tells them, so I want the program to send an alert message to the other computers telling them that an intake has been sent.
Now I've done some research into this and figured that TCP is the way to go since it's reliable. I also know that this is a one-to-many sending going on, so I assume that my Intake program will act as the server an the other computers will be the client, or should it be the other way around?
Now I assume that I have to create a client program that listens to the server and waits for it to send a message.
With that in mind, how do I:
Create a client program that listens for the message continuously until the program is closed. I assume that I'll be using "while (true)" and sleep. If so, how long do I put the program to sleep?
Make it as part of Windows service so that can load up when Windows start.
On the server end, how do I:
Send messages to more than one computer, since TCP is not capable of multicasting or broadcasting. I assume an array/vector will play a part here.
Oh, this is a one-way communication. The client doesn't have to respond back to the server.
First of all, UDP is quite reliable (in fact, as reliable as the IP protocol itself). TCP simply ensures that the data was received which involved quite a lot of magic in the back end. Unless you absolutely need to be sure that other machines got the message, you could do it with UDP. Mind that I'm not saying “Don't use TCP”, I just want to make it straight that you should take UDP into consideration as well.
Anyway, yes, you can create a simple listening program. Here is an example of a client in Java that reads messages from the server. It overrides the run method of a Thread class:
public void run() {
try {
String messageFromServer = reader.readLine();
while (messageFromServer != null) {
// Do things with messageFromServer here
// processor.processFromServer(messageFromServer);
messageFromServer = reader.readLine(); // Blocks the loop, waits for message
}
}
catch (IOException e) {
// Handle your exception
}
}
Amongst other things, my thread was set up as such:
public CommunicationThread(String hostname, int port, int timeout) throws IOException, SocketTimeoutException {
InetSocketAddress address = new InetSocketAddress(hostname, port);
socket = new Socket();
socket.connect(address, 2000); // 2000ms time out
// You can use the writer to write messages back out to the server
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
Now, regards to server-side you can do something as follows:
Write a program to allow clients to contact, given that they know your address.
Accept the connections, and store the sockets in a list.
When you need to send out a message, traverse the list and send the data to everyone on it.
You can start listening on your server with
this.socket = new ServerSocket(port);
You could (or even should(?)) make it threaded so that you can accept clients while serving others. You can accept new clients with:
socket.accept(); // Blocks, waiting for someone to connect, returns open socket
Feel free to pass that to a whole new class which can deal with BufferedWriter (and maybe even BufferedReader if you want to read from clients as well). That class is where you would implement things such as writeToClient(message)
Consider the situation where you have a ClientConnection class that has writeToClient(String s) method and (Server server, Socket socket) and initialized ArrayList conList.
Here is how you would follow:
In a separate thread in Server, accept connections with
ClientConnection con = new ClientConnection(this, socket.accept());
conList.add(con);
Then, when you want to write to clients:
for (ClientConnection c : conList) {
c.writeToClient("I'm sending you a message!");
}
I hope you get a vague idea of what you need to do. Read the Socket documentation, it's very useful. Also, as always with threaded applications, make sure you aren't doing things such as modifying a list while traversing it and avoid race conditions.
Good luck!

Java Socket Connections in Queue

I have a client/server set up. The server (Provider.java) will accept 2 Socket connections. Each client, after they connect, are asked what type of game they would like to play - Tic Tac Toe, Chess, or Connect 5. Depending on their answer, the Socket connections are then stored in the particular game Queue. So, Tic Tac Toe has a Queue, and Connect 5 has a Queue, etc.
The Queues are implemented as follows:
Queue<Socket> qTTT = new LinkedList<Socket>();
Queue<Socket> qC5 = new LinkedList<Socket>();
Queue<Socket> qChess = new LinkedList<Socket>();
Each time a connection is added, the queues are checked to see if there are two connections. If there are two connections in a particular queue, then a game of that type will be launched, with the two connections. (designed with Factory design pattern).
if (qTTT.size() == 2) {
ObjectOutputStream out = null, out2 = null; // Client 1, Client 2
ObjectInputStream in = null, in2 = null; // Client 1, Client 2
Socket connection1 = null, connection2 = null;
connection1 = qTTT.remove();
connection2 = qTTT.remove();
try {
out = new ObjectOutputStream(connection1.getOutputStream());
out2 = new ObjectOutputStream(connection2.getOutputStream());
in = new ObjectInputStream(connection1.getInputStream());
in2 = new ObjectInputStream(connection2.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
SimpleGameFactory factory = new SimpleGameFactory();
GameStore store = new GameStore(factory);
Game game = store.orderGame("TTT");
System.out.println("We ordered a " + game.getName() + "\n");
tgame.setObject(game);
tgame.setSockets(connection1, connection2);
tgame.setStreams(in, out, in2, out2);
// Start the threaded game
tgame.start();
}
The above is throwing some sort of Stream corruption error. Here are my questions:
First, when the clients first connect, the socket connections are associated with an ObjectInputStream and an ObjectOutputStream. Those streams are not passed into the queue with the connections, so in the code above, new streams are assigned to the connections. Then, those streams are passed into the threaded game to start the game. Am I allowed to do this (assign new streams to the connections)? After streams had already been assigned to them?
Second, am I storing/removing the socket connections in the queue properly?
Thanks for your help!
UPDATE:
Here is the error I have been getting:
java.io.EOFException
at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2232)
at java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:2698)
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:750)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:268)
at Pools.check_pools(Pools.java:34)
at Provider.start(Provider.java:85)
at StartServer.main(StartServer.java:16)
Turns out that I cannot assign an additional set of Input/Output streams to socket connections which have already been assigned a set of streams.
Thanks all for your help!
Honestly, that question looks like a solution to a college assignment.
Hint: write simple publisher/subscriber first. Set up one process that will be writing hello world to a socket and the second process that will be reading out of this socket. Then take it from there. I bet you're missing something obvious :-)
Are you sure that all of the opening handshake was retrieved from the socket before constructing the Object IO streams?
For example, if the client sends TTT\n\n as the game request and your code only reads the TTT\n and leaves the other \n on the stream, then the ObjectInputStream will fail.
You don't show the part where the user's game choice is read from the socket. So, this is just a guess.
My guess is that the exception has something to do with the code that you described at the beginning of your post. I'd start by looking into what you're doing with the sockets before your program gets to that snippet of code you posted.

Categories