I was trying to do a chat and I notice that readUTF() and writeUTF() did not work. readUTF() stays waiting when I already used writeUTF(). I made a simple test and does not work, what I am doing bad?
(I know that I could use Data Streams instead of Object Streams but in my chat I want to write objects and strings)
Server code:
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(40001);
Socket s = server.accept();
ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream());
ObjectInputStream in = new ObjectInputStream(s.getInputStream());
System.out.println(in.readUTF());
out.writeUTF("E");
}
}
Client code:
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
Socket s = new Socket("localhost", 40001);
ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream());
ObjectInputStream in = new ObjectInputStream(s.getInputStream());
out.writeUTF("A");
System.out.println(in.readUTF());
}
}
I could use writeObject("A") and cast the String with readObject(), but I want to know why this way does not work.
You need to call flush() after writing using writeUTF. The reason that writeObject just seems to work is that writeObject will switch to a specific mode before it starts writing, and switch back after it is done. This switching back will automatically flush the buffered data (at least in Java 11). This is not the case for writeUTF, and an explicit call to flush() is needed.
ObjectOutputStream uses an internal buffer, so you should try out.flush() after writes if you want content to be available to read on the InputStream.
The javadoc for ObjectOutputStream includes:
callers may wish to flush the stream immediately to ensure that constructors for receiving ObjectInputStreams will not block when reading the header
Related
I'm trying to perform communication between server and client using Genson library. I've detected the following problem: trying to send a message to the server my application stalls when genson on the server is trying to read the message.
Meanwhile, if I shutdown the client, the message is perfectly read and processed. I've thought it to be deadlock but not sure.
There is no such a problem with native Java serialization.
Here is my server:
import com.owlike.genson.Genson;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
public class Server {
public static void main(String[] args) throws IOException {
Genson genson = new Genson();
try (ServerSocket server = new ServerSocket(9991)) {
try (Socket socket = server.accept()) {
int[] loc = genson.deserialize(socket.getInputStream(), int[].class);
System.out.println("Server: " + Arrays.toString(loc));
genson.serialize(loc, socket.getOutputStream());
}
}
}
}
Here is the client:
import com.owlike.genson.Genson;
import java.io.IOException;
import java.net.Socket;
import java.util.Arrays;
public class Client {
public static void main(String[] args) throws IOException {
Genson genson = new Genson();
try (Socket socket = new Socket("localhost", 9991)) {
genson.serialize(new int[] {1, 2, 3}, socket.getOutputStream());
int[] loc = genson.deserialize(socket.getInputStream(), int[].class);
System.out.println("Client: " + Arrays.toString(loc));
}
}
}
I wound highly appreciate any help with this question. Thanks in advance.
Edit: This is really wierd. I've made some additional tests and here is what i get:
Additional class:
import com.owlike.genson.annotation.JsonProperty;
import java.io.Serializable;
public class Tester implements Serializable {
public static final Tester TEST = new Tester(Math.E);
private double val = Math.PI;
public Tester(#JsonProperty("val") double val) {
this.val = val;
}
public Tester() {}
public String toString() {
return "" + val;
}
}
Having written genson.serialize(Tester.TEST, socket.getOutputStream()) in the client request I have the same strange result. But having written genson.serialize(new Tester(Double.NaN), socket.getOutputStream()) the result is the expexted one.
Furthermore, if I define the only field in Tester class to be of type int[], lets say, it only works with values of null or new int[0].
In addition to that, if I'm trying to serialize and transmit int for integers in range 0..9 I observe the following behaviour: the same strange thing except that when I shutdown the client, server always shows 0 value.
Besides, for constants like Double.NaN, Double.POSITIVE_INFINITY, Integer.MAX_VALUE and similar there is nothing strange at all (everything works as expected).
For those additional tests Genson class was defined as follows:
Genson genson = new GensonBuilder()
.useMethods(false)
.setFieldFilter(VisibilityFilter.PRIVATE)
.create();
Note that there is no such issue when ser/deser to/from a file using streams:
import com.owlike.genson.Genson;
import com.owlike.genson.GensonBuilder;
import com.owlike.genson.reflect.VisibilityFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class FileTest {
private static final String FILENAME = "test.json";
public static void main(String[] args) throws IOException {
Genson genson = new GensonBuilder()
.useMethods(false)
.setFieldFilter(VisibilityFilter.PRIVATE)
.useIndentation(true)
.create();
try (OutputStream stream = new FileOutputStream(FILENAME)) {
genson.serialize(Tester.TEST, stream);
}
try (InputStream stream = new FileInputStream(FILENAME)) {
System.out.println(genson.deserialize(stream, Tester.class));
}
}
}
Looks like it was a mistake of mine all the time. I've forgotten that socket's stream can't be closed (unless you want to close the socket too). So in this case Server tries to get as much data from InputStream as it can but it can't consume all the stream (because it is always opened and data can be sent at any time from the client). So the Server basically freezes waiting for data but there is no more data to come. As a result we have the very situation described above.
A solution would be to specify some kind of protocole to denote query size so the Server can know how much data it should consume. See this answer for more details.
Some code paths in the reading API will try to eagerly ensure that there are at least N bytes available or EOF has been reached. This happens all the time when parsing a number (that is not a constant) as you noted.
An option could be to implement a small layer that serializes to a byte array or string, gets the message length and writes it to the output, followed by the payload. On the reading side you would first read the length and then read from the stream in a while loop until you reached that length or EOF.
Then you would just pass to Genson.deseralize this in memory message.
I have created a simple class which sends a string to a server, both communicate using Java Sockets API. The server reads what the client have sent, and responds with another string. But the client can not read that response.
This is the client class:
import java.io.IOException;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost", 8181);
socket.getOutputStream().write("Hello".getBytes());
int read;
while ((read = socket.getInputStream().read()) > -1) {
System.out.print((char) read);
}
socket.close();
}
}
And this is the server class:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8181);
while (true) {
Socket socket = serverSocket.accept();
int read;
while ((read = socket.getInputStream().read()) > -1) {
System.out.print((char) read);
}
socket.getOutputStream().write("Hi!".getBytes());
}
}
}
I imagine that the problem may be in the client execution flow, because I don`t know how canI do it wait for a server response. In other words, how to implement a client able to read the server response?
You aren't closing the sockets.
The server is attempting to read until end of stream and then send a reply. End of stream only happens when the peer closes the connection, so it won't be possible to send a reply even after you fix (1). You need to read a message, whatever that means in your application protocol.
You need to flush or close the outputstream.
i want to know the functionality of sockets in java. when i am creating some http-server i can use some ready to use sockets for secure and non-secure communication between two parties. but i never installed tomcat to my project, so my question is: how can java create a tcp / ip connection without a web-server? Can someone post me some link to clear this question?
In my case i used this to create a SSLSocket:
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import javax.net.ssl.SSLServerSocketFactory;
public class MainClass {
public static void main(String args[]) throws Exception {
SSLServerSocketFactory ssf = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
ServerSocket ss = ssf.createServerSocket(5432);
while (true) {
Socket s = ss.accept();
PrintStream out = new PrintStream(s.getOutputStream());
out.println("Hi");
out.close();
s.close();
}
}
}
Thank u a lot,
Mira
I was wondering if i could get help making or finding a program that has the ability to send keyboard presses and receive them on another computer. I want to use this to play multiplayer flash-player games with friends across computers. I know there are some programs out there like "logmein" but both users cannot use the keyboard at the same time. (When i press a key the computer user cannot press a key at the same time because it wont respond.) I only know java and I am quite novice at it. Im guessing if i need to write it ill have to send the information through a port or onto a web-server. I would like to know your opinions and suggestions for this program, thanks guys.
Basically what you are looking for is a chatroom program? Have you tried looking into mIRC?
mIRC is a free internet relay chat. What exactly are the requirements for the program? Is there a certain size that it must be? Are these flash games that you and your friends are playing taking up your full computer screen?
Building a program would require a web-server(any computer with internet access would do), and you would have to open the ports on your network to allow the traffic to go through.
A basic server in java would look something like this:
Please note that after the first connection this "server" will close the connection.
import java.net.ServerSocket;
import java.net.Socket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Server
{
private static ServerSocket serverSocket;
private static Socket clientSocket;
private static BufferedReader bufferedReader;
private static String inputLine;
public static void main(String[] args)
{
// Wait for client to connect on 63400
try
{
serverSocket = new ServerSocket(63400);
while(true){
clientSocket = serverSocket.accept();
// Create a reader
bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// Get the client message
while((inputLine = bufferedReader.readLine()) != null)
{System.out.println(inputLine);}
serverSocket.close();
System.out.println("close");
}
}
catch(IOException e)
{
System.out.println(e);
}
}
}
And a client would almost be the same:
import java.net.Socket;
import java.io.PrintWriter;
public class client
{
private static Socket socket;
private static PrintWriter printWriter;
public static void main(String[] args)
{
try
{
//change "localhost" to the ip address that the client is on, and this number to the port
socket = new Socket("localhost",63400);
printWriter = new PrintWriter(socket.getOutputStream(),true);
printWriter.println("Hello Socket");
}
catch(Exception e)
{
System.out.println(e);
}
}
}
If I am not mistaken printWriter is a 16-bit operation, and in order to reduce lag, if you were just sending text then you might want to use printStream(). I believe that this might be a bit quicker.
I want to write to a named pipe (already created) without blocking on the reader. My reader is another application that may go down. If the reader does go down, I want the writer application to keep writing to that named pipe. Something like a this in Java
fopen(fPath, O_NONBLOCK)
So that when the reader comes up, it may resume from where it failed.
First I try to answer your questions. Next I will try to show you a code snippet I created that solves your problem using blocking IO.
Your questions
I want to write to a named pipe
(already created) without blocking on
the reader
You don't need non blocking IO to solve your problem. I think it can not even help you solve your problem. Blocking IO will also run good(maybe even better then non blocking IO because of the low concurrency). A plus is blocking IO is easier to program. Your reader can/should stay blocking.
My reader is another application that
may go down. If the reader does go
down, I want the writer application to
neep writing to the named pipe. So that when the reader comes up, it may resume from where it failed.
just put the messages inside a blocking queue. Next write to the named pipe only when the reader is reading from it(happens automatically because of blocking IO). No need for non-blocking file IO when you use a blocking queue. The data is asynchronous delivered from the blocking queue when a reader is reading, which will sent your data from your writer to the reader.
Something like a fopen(fPath,
O_NONBLOCK) in Java
You don't need non-blocking IO on the reader and even if you used it. just use blocking IO.
CODE SNIPPET
A created a little snippet which I believe demonstrates what your needs.
Components:
Writer.java: reads lines from console as an example. When you start program enter text followed by enter which will sent it to your named pipe. The writer will resume writing if necessary.
Reader.java: reads lines written from your named pipe(Writer.java).
Named pipe: I assume you have created a pipe named "pipe" in the same directory.
Writer.java
import java.io.BufferedWriter;
import java.io.Console;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Writer {
private final BlockingDeque<StringBuffer> queue;
private final String filename;
public static void main(String[] args) throws Exception {
final Console console = System.console();
final Writer writer = new Writer("pipe");
writer.init();
while(true) {
String readLine = console.readLine();
writer.write(new StringBuffer(readLine));
}
}
public Writer(final String filename){
this.queue = new LinkedBlockingDeque<StringBuffer>();
this.filename = filename;
}
public void write(StringBuffer buf) {
queue.add(buf);
}
public void init() {
ExecutorService single = Executors.newSingleThreadExecutor();
Runnable runnable = new Runnable() {
public void run() {
while(true) {
PrintWriter w = null;
try {
String toString = queue.take().toString();
w = new PrintWriter(new BufferedWriter(new FileWriter(filename)), true);
w.println(toString);
} catch (Exception ex) {
Logger.getLogger(Writer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
single.submit(runnable);
}
}
Reader.java
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Reader {
private final BufferedReader br;
public Reader(final String filename) throws FileNotFoundException {
br = new BufferedReader(new FileReader(filename));
}
public String readLine() throws IOException {
return br.readLine();
}
public void close() {
try {
br.close();
} catch (IOException ex) {
Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) throws FileNotFoundException {
Reader reader = new Reader("pipe");
while(true) {
try {
String readLine = reader.readLine();
System.out.println("readLine = " + readLine);
} catch (IOException ex) {
reader.close();
break;
}
}
}
}
If you want pipes to stay active and queue up messages, you probably want a messaging system rather than a raw pipe. In Java, the standard API is called "Java Messaging System" (JMS), and there are many standard implementations-- the most common of which I've seen being Apache ActiveMQ. If you want a cross-platform, sockets-like interface that does buffering and recovery I might suggest 0MQ, which while not being "pure Java" has bindings for many languages and excellent performance.
If there was such a thing as non-blocking file I/O in Java, which there isn't, a write to a named pipe that wasn't being read would return zero and not write anything. So non-blocking isn't part of the solution.
There's also the issue that named pipes have a finite buffer size. They aren't infinite queues regardless of whether there is a reading process or not. I agree with the suggestion to look into JMS.
You should be able to use NIO's asynch write on a UNIX FIFO, just as you can to any other file:
AsynchronousFileChannel channel = AsynchronousFileChannel.open(...);
Future<Integer> writeFuture = channel.write(...);
... or...
channel.write(..., myCompletionHandler);
However, it's not clear to me what you want to happen when the FIFO isn't accepting writes. Do you want it to buffer? If so you'll need to provide it within the Java program. Do you want it to time out? There's no simple timeout option on Java file writes.
These aren't insurmountable problems. If you're determined you can probably get something working. But I wonder whether you'd not find life much easier if you just used a TCP socket or a JMS queue.