Socket unable to receive data - java

I have a class implementing serversocket class and there is another class implementing the client 1. Socket class.
So what I am trying to do is that. After getting the streams I want client to send a number to server and server will in turn respond to client whether it's prime or not. Which is display in an awt.Label.
But I am not able to receive any response.
Here is the code for client's constructor:
public ClientIsPrime()
{
setLayout(new GridLayout(2,2));
add(new Label("Enter a number: "));
add(numEntry=new TextField(10));
add(checkPrime=new Button("Check if number is Prime"));
add(result=new Label("Result is shown here"));
try
{
Socket client = new Socket(InetAddress.getLocalHost(), 5959);
in=client.getInputStream();
out=client.getOutputStream();
}catch(UnknownHostException e)
{
result.setText("Local Host cannot be resolved");
}catch(IOException e)
{
result.setText("IOException occured");
}
checkPrime.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
try
{
int num;
num=Integer.parseInt(numEntry.getText());
out.write(num);
out.flush();
int c;
result.setText("");
String s="";
while((c=in.read())!=-1)
s+=((char)c);
result.setText(s);
}catch(IOException e)
{
result.setText("IOException occured");
}catch(NumberFormatException e)
{
result.setText("Please enter a valid number.");
}
}
});
}
Code for Server:
public static void main(String args[])throws IOException
{
server=new ServerSocket(5959);
socket=server.accept();
System.out.println("connected");
InputStream in=socket.getInputStream();
OutputStream out=socket.getOutputStream();
int c; String numStr="";
while((c=in.read())!=-1)
numStr+=((char)c);
int num=Integer.parseInt(numStr);
if(num==3)
out.write("Number is Prime".getBytes());
else
out.write("Number is not Prime".getBytes());
out.flush();
in.close();
out.close();
}
It isn't a real app. I am learning.

A few problems.
First your server implementation will never exit the while loop. The API for InputStream.read() states that it will block until data is received or the stream is closed. The stream is never closed so the reading will block forever after reading the initial data.
To solve this problem you must decide what your protocol is. See below.
The other problem is that you are writing from the client as a parsed int of text. So say 13 (as an int). But you are then reading it as if it were a sequence of characters. 13 on the wire will be read as some control character. You need to be consistent with how you write data and read data.
My suggestion would be to have a basic protocol. Use DataOutputStream on the writing side and DataInputStream on the reading side and then match the read/write calls on both sides to ensure you are consistent.

If you want to sent integers across the wire it is infinitely easier to layer a DataOutputStream/DataInputStream on top of the raw socket streams and just do writeInt() and readInt()

Related

Java message is sent to a closed socket

I have a client program that sends messages typed in console to the server. Following some advices, I introduced a check for a closed socket with Socket.checkError(). Nevertheless, for some reason it indicates error only after second failed attempt to send a message.
My code:
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
while (true)
try (
Socket clientSocket = new Socket(hostname, port);
PrintWriter socketOut = new PrintWriter(clientSocket.getOutputStream(), true);
) {
String input;
while ((input=stdIn.readLine())!=null) {
socketOut.println(input);
if (socketOut.checkError()) {
System.out.println("Got socket error");
break;
}
}
} catch (IOException e) {
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {}
}
I shut down (manually) my server side after receiving 'message1'. Therefore, I expect to get the error while trying to send the very next message. Nevertheless it occurs only one message after:
message1
message2
message3
Got socket error
Can anyone explain this behavior and advise me a method to get notification right on the first attempt to send a message in void?
Following some advices, I introduced a check for a closed socket with Socket.checkError().
There is no such method. Clearly you are referring to PrintWriter.checkError().
Nevertheless, for some reason it indicates error only after second failed attempt to send a message.
The reason is that there is both a socket send buffer at the sender and a socket receive buffer at the receiver, and that sending is asynchronous: it therefore isn't possible for the first send to detect an error.
Can anyone explain this behavior and advise me a method to get notification right on the first attempt to send a message in void?
There isn't one. That's the nature of TCP. What you are attempting indicates an application protocol error, and the answer lies in the realm of the application protocol as well: don't have the peer close the socket while this end could still be sending data, OR don't allow this end to send data after the peer has indicated, via the application protocol, that it won't be reading any more data.
Don't use PrintWriter over the network. It suppresses the actual exception. Use BufferedWriter and the write() and newLine() methods.
In ths java library there is no method to check if connection is opened or not. Method like isConnected() and isClosed() check only one side of the connection (where you invoked the method).
From javadoc:
Note: Closing a socket doesn't clear its connection state, which means
this method will return true for a closed socket (see isClosed()) if
it was successfuly connected prior to being closed.
To check if the connection has been really closed simply invoke the read() method (or equivalent) and check if it returns -1.
Note: also if isConnected will work as you like (giving false if the other side of the socket closed the connection or if there is a network problem or similar) the sequence:
if (socket.isConnected()) {
int x = socked.read();
}
will not grant that the x has a value different from -1 or throws an IOException, because the connection could be closed after the isConnected test and before the read operation.
The following code to show how any kind of check on the socket cannot guarantee that a subsequent read will give a valid result.
// Return true because socket communication is enabled
if (myFunctionToCheckIfSocketIsOpen(socket)) {
// Here the peer closed the socket or the network shutdown
// This read will give -1 or throws IOException also if the previous check returned true
int x = socket.read();
}
From the answer of #Davide Lorenzo MARINO I got the idea of employing read(). The only problem that it is blocking. However, one can always run it in another thread, which would modify a class global variable, when read() finally returns -1:
static boolean socketIsAlive;
...
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
while (true)
try (
Socket clientSocket = new Socket(hostname, port);
PrintWriter socketOut = new PrintWriter(clientSocket.getOutputStream(), true);
) {
socketIsAlive=true;
new ConnectionChecker(clientSocket).start();
String input;
while (true) {
if ((input=stdIn.readLine())!=null)
socketOut.println(input);
if (!socketIsAlive) {
System.out.println("Got socket error");
break;
}
}
} catch (IOException e) {
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {}
}
}
...
static public class ConnectionChecker extends Thread{
Socket socket;
public ConnectionChecker(Socket socket) {
this.socket=socket;
}
#Override
public void run() {
try {
if (socket.getInputStream().read()==-1)
socketIsAlive=false;
} catch (IOException e) {}
}
}

Why isn't my Socket closing on server side?

I'm trying to make a simple text editor which can be shared accross multiple terminals at the same time. I have a Server waiting for new users, when a user enters the shared editor it just starts waiting for input characters.
public class Server {
public static final int PORT = 8080;
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(PORT);
while (true) {
Socket socket = ss.accept();
System.out.println("A new user entered the sever");
new Thread(() -> serve(socket)).start();
}
}
private static void serve(Socket socket) {
try {
while (!socket.isClosed() && !socket.isInputShutdown()) {
System.out.println("hey " + socket.isClosed() + " " + socket.isInputShutdown());
System.out.print(new String(SocketUtil.receiveBytes(socket,1)));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
When a user closes the editor, the socket is closed on client side. However, the socket on the server side does not get closed and the server starts looping infinitly in the "wait for input" loop.
The Client is a singleton containing the following methods, called at the openning and closing of the editor.
public static void init() {
try {
if (socket == null) socket = new Socket(HOST,Server.PORT);
} catch (IOException e) {
e.printStackTrace();
kill();
throw new Error(e.getMessage());
}
}
public static void kill() {
Check.notNull(socket);
try {
SocketUtil.terminateCommunication(socket);
System.out.println(socket.isClosed());
} catch (IOException e) {
e.printStackTrace();
}
}
Finally, here are utilitary methods (in SocketUtil) used in both classes :
public static void terminateCommunication(Socket socket) throws IOException {
socket.shutdownInput();
socket.shutdownOutput();
socket.close();
}
public static char[] receiveBytes(Socket socket, int nBytes) throws IOException {
char[] bytes = new char[nBytes];
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
isr.read(bytes);
return bytes;
}
Any idea of why the socket on server side is not closed after the Client gets killed ?
It is not quite clear from the Javadoc, but isClosed() only returns true when you have explicitly called close() on the socket (see the sources to confirm that). You should check for exceptions and the return value of read() instead. If you read -1 or catch an IOException while trying to read (or write, for that matter), it essentially means that the other side has closed the connection, so you should close your socket as well (better to it in a finally block) and you're done with that particular connection. You don't check for -1 in receiveBytes(), but you really should. Perhaps throw a EOFException() if you want to merge these two possibility into one, so that the code up the stack (in serve()) doesn't have to figure out what exactly happened:
public static char[] receiveBytes(Socket socket, int nBytes) throws IOException {
char[] bytes = new char[nBytes];
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
if (isr.read(bytes) == -1)
throw new EOFException();
return bytes;
}
One exception from the IOException rule (sorry for the pun) is the SocketTimeoutException. If you get this, the connection is still alive, and you may just as well retry your read(). But I believe that in order to get these, you must call Socket.setSoTimeout() somewhere, and if you haven't, then you probably shouldn't worry about SocketTimeoutException.
You should also note that read() may sometimes return partial reads (that is, less than bytes.length). If it's important that receiveBytes() reads exactly nBytes (which probably is, since you never return the number of actual characters read), then you should call it in a loop, like this:
int pos = 0;
while (pos < bytes.length) {
int l;
if ((l = isr.read(bytes, pos, bytes.length - pos)) == -1) {
throw new EOFException();
}
pos += l;
}
I know this is cumbersome, which is exactly why many developers create utility methods like your receiveBytes().
The proper way to detect that the client has closed its connection is by checking the reception of 0 bytes.
System.out.print(new String(SocketUtil.receiveBytes(socket,1)));
just check if the string is empty should do the trick.
Note that I am not that familiar with java, but I do know socket programming.
Receiving 0 bytes, checking for that, and closing the socket if you do is a good solution.
You can use exception handling too, but you'll detect that the peer closed it socket an iteration later. Receiving 0 bytes is not really an error condition it is just a signal from the peer that he has closed its end of the socket and won't send anymore data. If you ignore this, and keep using the socket, you'll receive an exception in the next iteration because there is nothing to receive anymore.

Scanner.nextLine() blocks when using InputStream from Socket

When I receive data using Socket.getInputStream() directly (without some kind of interface like Scanner), it doesn't block. But, when I try to use a Scanner (similar to how we receive Strings from System.in), it does. I was wondering the reason for this, and how the InputStream that a connected Socket supplies to you is different from the InputStream in in System.
The Client used for testing (used for both servers)
The code that hangs:
public class Server {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(15180);
Socket socket = ss.accept();
Scanner scanner = new Scanner(socket.getInputStream());
//read data from client
while(true) {
String data = scanner.nextLine();
System.out.println("Received data!");
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
The code that doesn't block:
public class Server {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(15180);
Socket socket = ss.accept();
//read data from client
while(true) {
int data = socket.getInputStream().read();
System.out.println("Received data!");
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
(I think you've already figured this out but ...)
The readLine() method returns the rest of the current line. That is, all unconsumed characters up to the next "end of line" sequence, or the "end of stream", which ever comes first. It will block, waiting until the current line (according to the above) is available.
So if your socket readLine() call blocks, it is waiting for the remote to either send an end-of-line marker (e.g. '\n'), or close its socket output stream (which will result in an "end-of-stream" at this end).
Q: Why does it "work" when you read from the console?
A: The console adds an "end-of-line" sequence to the stream whenever you hit ENTER. (Precisely what sequence is added is OS dependent, but the Scanner class will cope with all common varieties, and some unusual ones too.)
The lesson here is that you should only use Scanner.readLine() if the input stream is line oriented; i.e. if whatever wrote / generated the stream is including "end-of-line" markers.

Java - closing socket gives different results

I'm getting different results while trying to read from a socket while the other socket is closed.
I have two sockets A and B.
1)B sent some data to A --> A has read the data --> A closes --> When B tries to read some data from A, it is getting -1(or EOF).
2)B sent some data to A --> A closes even before reading the data --> Now B tries to read from A, an exception is thrown(java.net.SocketException "Software caused connection abort.")
please excuse me, if you can't understand my question. Please see the code
Server.java
import java.io.*;
import java.net.*;
class SocketCloser extends Thread
{
private Socket c;
public SocketCloser(Socket c) {
this.c = c;
}
public void run() {
try{
this.c.close();
} catch (Exception e) {}
}
}
public class Server
{
public static void main(String argv[]) throws Exception {
ServerSocket listen = new ServerSocket(6789);
Socket socket = listen.accept();
SocketCloser sc = new SocketCloser(socket);
InputStream is = socket.getInputStream();
// uncomment below line to get "Software caused connection abort" on client
//sc.start();
try {
Thread.sleep(1000);
int i = is.read();
System.out.println("read returned: " + i);
socket.close();
} catch (Exception e) {
System.out.println(e.toString() + " thrown");
}
}
}
Client.java
import java.io.*;
import java.net.*;
public class Client
{
public static void main(String argv[])
{
Socket cSocket;
try {
cSocket = new Socket("localhost", 6789);
InputStream is = cSocket.getInputStream();
OutputStream os = cSocket.getOutputStream();
Thread.sleep(1000);
os.write(200);
Thread.sleep(1000);
int i = is.read();
System.out.println("read returned: " + i);
cSocket.close();
} catch (Exception e) {
System.out.println(e.toString() + " thrown");
}
}
}
Can someone please help me figure out why there is an exception in one case and -1 in another. Interestingly on linux both the cases resulted in -1.
1) Because B established a connection, A goes to CLOSE_WAIT. It will be in that state until B closes the connection. There is nothing to read, so the read() call on B's InputStream returns -1.
2) A is blocked in the accept call. The other thread is trying to close the socket, but it can't because accept is blocking it. When B connects, accept unblocks and the socket closes outright. When B tries to read, the socket is not there anymore so you get the exception.
I'm simplifying a bit, but that's the gist of it.
1)B sent some data to A --> A has read the data --> A closes --> When B tries to read some data from A, it is getting -1(or EOF).
I agree. What did you expect? This is the expected behaviour.
2)B sent some data to A --> A closes even before reading the data --> Now B tries to read from A, an exception is thrown(java.net.SocketException "Software caused connection abort.")
I agree. This is one of the expected behaviours in this incorrect situation. What did you expect?
please excuse me, if you can't understand my question.
There is no question here to understand. You haven't asked a question. You close a socket without sending any data and the peer gets EOS without receiving any data. You close a socket while the peer is sending and the peer gets an exception. System is working as designed.

java TCP socket message breaks

i have a java client-server app in java, both using the same connection class that contains both send/receive messages.
for some reason, some of the messages i send are received in a malformed order:
here's the code
//set up
_in = new BufferedReader(new InputStreamReader(this._socket.getInputStream()));
_out = new BufferedWriter(new OutputStreamWriter(this._socket.getOutputStream()));
this._socket.setSoTimeout(S_TIMEOUT);
public synchronized boolean send(String message){
try {
_out.write(message);
_out.write(Connection.DELIMITER);
_out.flush();
return true;
} catch (IOException e) {
}
return false;
}
public String receive(){
int c;
try {
String message = "";
System.out.println("Getting message:");
c = _in.read();
while(c != -1 && c != Connection.DELIMITER) {
message += (char) c;
c = _in.read();
}
if (c == -1) {
return null;
}
return message;
} catch (IOException e) { }
return null;
}
some messages, for example "new_order" will might return with "ew_ord".
some characters are lost, others are sent separately. this seems odd as its TCP
could this be an encoding related issue?
Delimiter is (char) 0
socket timeout is 20000 (ie 20 senconds). every 10 seconds i send an empty message to make sure socket does not close
EDIT:
although it was solved using the Scanner, i must say that the original code worked fine for many messages/various machines for a very long time (a few weeks), and then suddenly failed to work with one specific message on one specific machine (other messages went through just fine). i've done socket data transfer in java MANY times and i've written many read/write methods to handle the sockets. it's the first time i ran into this.
although in the original code i set the encoding (in the posted code i didn't), i believe that the problem was encoding related. at one point, the message that was received had every second character missing. afterwards i changed it a bit, and the first/second character of the message were received in a separate message. from my understanding, it's either an encoding issue or some firewall/other security program that was running on the message sender machine, that decided to filter outgoing packets.
Try replacing your receive with a Scanner and let it do the work for you.
// in your setup
Scanner sc = new Scanner(_in).useDelimiter(Connection.DELIMETER);
public String receive() {
try {
return sc.next();
} catch(IOException e) {
return "";
}
}
For starters, I would make sure you're printing exceptions in those catch blocks.
Then, you're using the platform default encoding for converting characters to bytes. If these two processes are running on different machines, it's possible they're using different encodings. I would make sure you're specifying an encoding when you set up the Reader and Writer.
You can use UTF encoding for getting Full String of Message.
U can try this code and I am Sure About this code because i used it in My Chat Application.
String data=" ";
socket = new Socket("localhost",999);
while(true)
{
dos = new DataOutputStream(socket.getOutputStream());
dis = new DataInputStream(socket.getInputStream());
data = dis.readUTF();
jta.append(data +"\n");
}
Where jta is JTextArea.
It's for Client Side
Now For Server Side:
try
{
server = new ServerSocket(999);
Socket soc = server.accept();
while(true)
{
String data="";
try
{
dis = new DataInputStream(soc.getInputStream());
dos = new DataOutputStream(soc.getOutputStream());
data = dis.readUTF();
}
catch(Exception e)
{ }
jta.append(data + "\n");
}
}
catch (IOException e)
{
JOptionPane.showMessageDialog(this, e);
System.exit(-1);
}

Categories

Resources