I got a socket listener which keep listening for data. The problem now is that the client which send data will finally close the connection by itself. Based on my codes below I am wondering do I still need to perform this part of the codes where it does writeBuffer.close();?
Should I remove the final part and just put the socket closing the catch?
public void run()
{
BufferedWriter writeBuffer = null;
BufferedReader readBuffer = null;
String message="";
try {
writeBuffer = new BufferedWriter(new OutputStreamWriter(receivedSocketConn1.getOutputStream()));
readBuffer = new BufferedReader(new InputStreamReader(receivedSocketConn1.getInputStream()));
int m = 0, count=0;
int nextChar=0;
while ((nextChar=readBuffer.read()) != -1)
{
message += (char) nextChar;
if (nextChar == '#')
{
System.out.println("\n\nSending PA : "+message);
writeBuffer.write("$PA\r\n");
writeBuffer.flush();
message="";
}
}
}
catch (Exception ex)
{
System.out.println("MyError:Exception has been caught in in the main first try");
ex.printStackTrace(System.out);
}
/*finally
{
try
{
if ( writeBuffer != null )
{
writeBuffer.close();
}
else
{
System.out.println("MyError:writeBuffer is null in finally close");
}
}
catch(IOException ex)
{
ex.printStackTrace(System.out);
}
}*/
}
It's always a good idea to explicitly close the connections you're using. Think about it, it might be possible that the client never closes the connection (of course, then you'd have to implement some kind of timeout mechanism that closes the connection on the server side after a certain amount of time, but that's a different matter).
My point is - it never hurts to be careful, and manage your resources in a conservative fashion.
Related
I have a buffered reader reading from a socket line by line. So this works fine. However this looks pretty low level to me and a telnet client is not able to close the connection sending a ctrl + c. So I am wondering if there is some nicer implementation of a stream reader? I.e. the whole tread and loop could easily be abstracted away and just call lambda functions on read, close and error. Or what is the best practice here?
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
new Thread(() -> {
while (true) {
try {
String readLine = bufferedReader.readLine();
// if readline is null then the client just closed connection
// if there is something in the buffer and the clients close the connection
// raadLine returns with anything left in the buffer up until the client left
// and returns a second time with null
if (readLine == null) {
logger.info("client closed connection");
socket.close();
disconnectAll();
break;
} else {
for (Listener listener : listeners) {
listener.messageReceived(this, readLine);
}
}
} catch (IOException | IllegalAccessException | InvocationTargetException e) {
logger.error(e.getMessage(), e);
try {
socket.close();
} catch (IOException e1) {
logger.error(e1.getMessage(), e1);
} finally {
disconnectAll();
break;
}
}
}
}).start();
I think your base problem is that sending Ctrl-C doesn't close a stream, Ctrl-D does. Edit: Ctrl-Z on Windows.
The remainder of the question really belongs to https://codereview.stackexchange.com/, but here goes.
Firstly, you are closing a socket that was opened outside.
Secondly, you shouldn't create Thread objects, but use an ExecutorService.
Third, I'd recommend using try-with-resource to ensure everything closes automatically.
Fourth, you can use the read line in your while statement instead of using while(true) - break.
This gives you something like
ExecutorService readerExecutor = Executors.newSingleThreadExecutor();
public startReadingSocket(Supplier<Socket> createSocket, Consumer<String> lineHandler, Consumer<Exception> excHandler, Runnable cleanUp) {
readerExecutor.submit(() -> {
String readLine;
try (Socket s = createSocket.get();
InputStreamReader isReader = new InputStreamReader(s.getInputStream());
BufferedReader reader = new BufferedReader(isReader)) {
while (readLine = reader.readLine() != null) {
lineHandler.accept(readLine);
}
System.out.println("client closed connection.");
} catch (Exception e) {
excHandler.accept(e);
} finally {
cleanUp.run();
}
}
}
And you can run that via
startReadingSocket(() -> new Socket(host, port),
line -> listeners.forEach(l -> l.messageReceived(this, line)),
ex -> logger.error(ex.getMessage, ex),
this::disconnectAll);
Now this is Java 8, with previous versions you'd need to create interfaces and anonymous classes for the lambdas.
I am creating a socket server for a school project. The client is written in C# so the ObjectInputStream object I have been using so far is not working.
I am now trying to use InputStreamReader. In this example, the while (true) loop is running at full throttle all the time. Using the ObjectInputStream it'd wait for an object to arrive.
How can I do this in a proper way?
private InputStreamReader inputStream;
#Override
public void run() {
while (true) {
try {
// ObjectInputStream.read() waits for an object to arrive,
// so the execution is paused here
int data;
String string = new String();
while ( (data = inputStream.read() ) != -1) {
char thisChar = (char) data;
string = string + thisChar;
}
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
break;
}
}
}
Get rid of the outer loop. It's pointless. The inner loop will run until end of stream. After that, further iteration is futile. You're spinning at EOS.
I'm having a little trouble with a simple Java server, client application.
Basically the topics says it all: when I do a writeUTF on the server side it only sends every 2nd time it's being executed.
For an example:
Server:
public class Server {
/**
* #param args
*/
public static void main(String[] args) {
try {
ServerSocket server = new ServerSocket(7777);
Socket client = server.accept();
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(client.getOutputStream()));
DataInputStream in = new DataInputStream(new BufferedInputStream(client.getInputStream()));
while(true) {
for(int i = 0; i < 100; i++) {
out.writeUTF("Test" + i);
out.flush();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
And client:
public class Client {
/**
* #param args
*/
public static void main(String[] args) {
try {
Socket client = new Socket("localhost", 7777);
DataInputStream in = new DataInputStream(new BufferedInputStream(client.getInputStream()));
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(client.getOutputStream()));
while(in.readUTF() != null) {
System.out.println(in.readUTF());
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
And the output in the console looks like this:
Test1
Test3
Test5
Test7
Test9
Test11
What is causing this behavior?
It's because you're discarding data on your client.
When you check while(in.readUTF() != null), you're reading an entry from the stream every time to see if it's non-null. Then you discard this value, and read a new one within the loop. (As well as losing values, this has the bug that with an odd number of total values, the while condition will evaluate to true but the next call to readUTF() would return null within the loop.)
To fix this, you should read the value to a variable, and test this before using it - something like the following:
String value;
while((value = in.readUTF()) != null) {
System.out.println(value);
}
If you don't like the assignment and nullity check as a single expression, you can instead assign value = in.readUTF() initially and at the end of every loop, but personally I find this more error-prone.
This loop
while(in.readUTF() != null) {
System.out.println(in.readUTF());
}
throws away every second string it reads. You read one string while testing for end of file, discard it, then read another one and print it.
You are consuming the data in the while loop evaluation here:
while(in.readUTF() != null) {
System.out.println(in.readUTF());
}
Try this instead:
String line;
while( ((line = in.readUTF()) != null) {
System.out.println(line);
}
If you want your socket in UTF-8
you only need to add "UTF-8" in BufferedWriter and BufferedReader's contstructor
here is the sample
this.basicReader = this.Client.getInputStream();
this.basicWriter = this.Client.getOutputStream();
this.Reader= new BufferedReader(new InputStreamReader(basicReader,"UTF-8"));
this.Writer= new BufferedWriter(new OutputStreamWriter(basicWriter,"UTF-8"));
how to send data
this.Writer.write("data"+"\r\n");
this.Writer.flush();
and your main problem is your client didnt respond a msg when your client receive a msg
server to client
client to server
server to client
like this, try it.
I have 2 sockets and I am using BufferedReader around it's InputStreams. What I am trying to do is take all input from the first socket and send it to the other socket (and visa versa).
The problem is that if the first one does not send a message, it will still block on the first readLine() even though the 2nd socket has already sent some data and is ready. I would like to continue with this simple approach of using no additional threads.
Here's some code that I wrote up, as you can see I have 2 BufferedReaders (in0 and in1) , the program gets stuck at in0.readLine() (blocking).
private void network()
{
PrintWriter out0 = null, out1 = null;
BufferedReader in0 = null,in1 = null;
try{
//clients[] is an array of Socket[2]
in0 = new BufferedReader(new InputStreamReader(clients[0].getInputStream()));
out0 = new PrintWriter(clients[0].getOutputStream(), true);
in1 = new BufferedReader(new InputStreamReader(clients[1].getInputStream()));
out1 = new PrintWriter(clients[1].getOutputStream(), true);
} catch (IOException e) {
System.out.println("Accept failed: 4445");
System.exit(-1);
}
int count = 1;
while(true)
{
System.out.println("network check loop # " + count);
++count;
String nextMessage = null;
try {
if( (nextMessage = in0.readLine()) != null)
{
this.relayMessage(nextMessage,out1);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Middle of network check loop");
nextMessage = null;
try {
if((nextMessage = in1.readLine()) != null)
{
this.relayMessage(nextMessage,out0);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
How can I just skip that statement if in0 is not ready to give me some data? I have seen BufferedReader's ready() method and have attempted to use in0.ready() && readLine() but this causes an infinite loop as neither of the bufferedreaders appear to ever be 'ready'. As well, I am certain that the messages being sent over the socket end in newline characters so readLine() should process correctly!
Any ideas?
Try to use setSoTimeout to put a timeout on your read(), then you just need to catch the SocketTimeoutException if the timer has expired.
Here break and continue keywords are your friends.
The simplest approach is to use two threads. This way you don't have to write your own scheduling code to determine which thread should be running. BTW: The code to copy from one socket to another is the same in each thread, reducing duplication.
To manage your threads I would use an ExecutorService which will make shutting downt eh threads easier.
First off let me apologize to the SO community for coming to you with something that ought to be so trivial. But I've been at this all day and I'm at the end of my rope.
There is a section of my program that needs pull text from an input stream and an error stream from a process that is launched using Runtime.getrunTime().exec() and pass it through to standard input and output in an orderly manner. I have a function that near as I can tell should work. But it seems to be getting caught in a catch-22 where it's waiting for the stream to report ready - but the stream has finished and is not reporting. I'm baffled. I can't think of another way to do this that fits my constraints and I'm rather skeptical that such a catch-22 can exist.
Here is my code:
private void forwardStreamtoStd(InputStream in, InputStream err)
throws IOException {
int c = -1;
BufferedReader inReader = new BufferedReader(
new InputStreamReader(in, "US-ASCII"));
BufferedReader errReader = new BufferedReader(
new InputStreamReader(err, "US-ASCII"));
boolean inFinished = false, errFinished = false;
try {
System.out.println("Begin stream read loop...");
while (!inFinished && !errFinished) {
if (!inFinished) {
while (inReader.ready()) {
if ((c = inReader.read()) == -1) {
inFinished = true;
}
else {
System.out.print((char) c);
}
}
}
if (!errFinished) {
while (errReader.ready()) {
if ((c = errReader.read()) == -1) {
errFinished = true;
}
else {
System.err.print((char) c);
}
}
}
}
System.out.println("End stream read loop.");
}
catch (IOException e) {
throw e;
}
finally {
errReader.close();
inReader.close();
}
}
The problem seems to be that the reading loops are waiting for the streams to report ready, and as a result aren't seeing the -1 returned by read telling them that it's time to quit. I'm trying to avoid having either stream blocking, so that I can pull from both in turn when they are prepared. However, how can I catch the process's end of stream? Am I missing something? Shouldn't read report that it's read when it has an end of stream -1? The processes are finishing, and so their streams should be dying. What am I doing wrong here?
There are two more possibilities:
Use the ProcessBuilder and invoke redirectErrorStream(true) to join the two streams and you need to read one stream. I have an example here.
In JDK7, you could call the inheritIO() to automatically forward everything
Edit On the second guess, it seems the ready() call is misleading your program. Try this:
private void forwardStreamtoStd(InputStream in, InputStream err)
throws IOException {
int c = -1;
BufferedReader inReader = new BufferedReader(
new InputStreamReader(in, "US-ASCII"));
BufferedReader errReader = new BufferedReader(
new InputStreamReader(err, "US-ASCII"));
boolean inFinished = false, errFinished = false;
try {
System.out.println("Begin stream read loop...");
if (!inFinished) {
while ((c = inReader.read()) != -1) {
System.out.print((char) c);
}
inFinished = true;
}
if (!errFinished) {
while ((c = errReader.read()) != -1) {
System.err.print((char) c);
}
errFinished = true;
}
System.out.println("End stream read loop.");
}
catch (IOException e) {
throw e;
}
finally {
errReader.close();
inReader.close();
}
}
Or better yet, leave off the BufferedReader if you don't plan any extra transformation:
private void createReader(final InputStream in, final OutputStream out) {
new Thread() {
public void run() {
try {
int c = 0;
while ((c = in.read()) != -1) {
out.write(c);
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
in.close();
}
}
}.start();
}
private void forwardStreamtoStd(InputStream in, InputStream err)
throws IOException {
createReader(in, System.out);
createReader(err, System.err);
}
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4090471
The solution I've always used is to create a separate thread to read one of the streams, join on the thread when the main thread finishes reading, and then waitFor the process.
It's essential to consume the 2 streams concurrently, to prevent blocking. See this article for more info, and in particular note the StreamGobbler mechanism that captures stdout/err in separate threads.
If I remember correctly, the spawned process will never close the stream - so you would need to have the readers in their own threads, sleep on the main thread until the process is done, and then close the readers.