I'm new to Java socket programming and I am doing a basic socket communication between an Android client and a Java server on the PC side. The server could receive the message from the client, but the client seems to have trouble reading messages from the server. I've been wondering why this is happening.
Server:
while(true){
try {
socket = serverSocket.accept();
dataInputStream = new DataInputStream(socket.getInputStream());
System.out.println("ip: " + socket.getInetAddress());
System.out.println("message: " + dataInputStream.readUTF());
dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF("Hello Client !!!!!!" + "\n");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
...
...
if (socket != null){
try{
socket.close();
socket = null;
}
catch(Exception e){
e.printStackTrace();
}
}
}
Client:
socket = new Socket(serverIP, 8080);
dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF(textOut.getText().toString());
dataInputStream = new DataInputStream(socket.getInputStream());
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
Log.i(TAG, dataInputStream.readUTF());
textIn.setText(dataInputStream.readUTF());
}
catch (Exception e) {
e.printStackTrace();
}
}
});
On server side everything works fine but the Android client just can't receive the data. readUTF does not return anything (also returns a W/System.err in the logcat)
Solution:
I finally resolved the problem by moving the dataInputStream.readUTF() out of the runOnUIThread section. eg. Store it in a temporary string before runOnUiThread. I guess this should be a noob mistake.
Also calling readUTF() in a row was definitely stupid enough.
the Android client just can't receive the data
Your client tries to read two messages, but only one is sent.
Also your server never closes the connection.
Related
I am developing a program that has a chat feature and I am using sockets in it.
In my case, I want to handle each of the client in a different window chat(PLEASE SEE ATTACHED IMAGE).
As of now, when 1 client is connected, there is no problem. But when 2 clients are connected, the first client will be overridden by the 2nd one and he can't receive messages from server not unless I close the connection for the latest client connected(Server still receiving messages from all client although only 1 client can receive from server).
How am I gonna do this? I am using captain casa framework
I want to manage it like what did the image below do.
IMAGE HERE
Here is my code:
Server:
public void mainserver(){
Thread server = new Thread(new Runnable() {
#Override
public void run() {
try {
serverSocket = new ServerSocket(port);
System.out.println("Server Online... \nWaiting for Connections");
} catch (IOException e) {
e.printStackTrace();
}
while (accept){
try {
socket = serverSocket.accept();
System.out.println("New Connection Estasblished!!!");
chatHandler chat = new chatHandler(socket);
chat.start();
} catch (IOException e) {
System.out.println("server not terminate all connections");
System.exit(-1);
}
}
}
});
server.start();
}
public class chatHandler extends Thread{
Socket socket;
public chatHandler(Socket socket){
this.socket = socket;
}
public void run(){
try {
din = new DataInputStream(socket.getInputStream());
dout = new DataOutputStream(socket.getOutputStream());
dout.writeUTF("Hi! Thank you for reaching us! How may I help you!?");
while (!read.equals(".end")){
read = din.readUTF();
if (getServerArea()!=null){
setServerArea(getServerArea()+"\n"+read);
}else {
setServerArea(read);
}
}
System.out.println("end of chat server");
} catch (IOException e) {
e.printStackTrace();
}finally {
System.out.println("Exit");
try {
dout.close();
din.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void serverSend(javax.faces.event.ActionEvent event) { // "Send" button
write = getServerField();
try {
dout.writeUTF(write);
dout.flush();
if (getServerArea()!=null){
setServerArea(getServerArea()+"\n"+write);
setServerField("");
}else {
setServerArea(write);
setServerField("");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(write);
}
Client:
public void client(){
Thread client = new Thread(new Runnable() {
#Override
public void run() {
try {
socket = new Socket("localhost",port);
din = new DataInputStream(socket.getInputStream());
dout = new DataOutputStream(socket.getOutputStream());
while (!read.equals("bye")){
read = din.readUTF();
if (getClientArea()!=null){
setClientArea(getClientArea()+"\n"+read);
}else {
setClientArea(read);
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
din.close();
dout.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
client.start();
}
public void clientSend(javax.faces.event.ActionEvent event) {
write = getClientField();
try {
dout.writeUTF(write);
dout.flush();
if (getClientArea()!=null){
setClientArea(getClientArea()+"\n"+write);
setClientField("");
}else {
setClientArea(write);
setClientField("");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(write);
}
I believe I understand the problem, and how to correct it.
You are using a unique thread (chatHandler) for each new connection.
This thread writes an automatic "Hello" upon connection, but thereafter is dedicated to reading messages (in the while loop you only read din) and updating the console accordingly. Since each thread is managing a reference to din, all incoming messages are OK.
However, it seems that writing back to a client (serverSend) is not in a thread; it is triggered by a button event. At this point, dout will be a reference to the most recent connection, and not a reference to the client intended to get the message. That is why the most recent client gets all future messages.
The correction is to choose the correct 'dout' for the intended client. When the server 'operator' chooses to write a message back (clicking the send button), somehow you need to obtain the correct 'dout' for that client.
One way to do this is to establish dout prior to creating the thread (using socket), and maintain a relationship between each client, and it's corresponding dout (i.e. in a Map).
If the problem is still not clear (that each client must have a unique reference to dout), please let me know and I will try to clarify.
I have a Server-Client program in Java where,in my Server UI I have two JLabel,when I Click on my 1st JLabel message is going to 1st Client but when I click it again message is not going to the client. Can someone point me out whats the mistake in my code?
//SERVER CODE
void connect_clients()
{
try {
ServerSocket listener = new ServerSocket(7700);
jButton1.setText("Server Running!");
jButton1.setEnabled(false);
try {
while (true) {
socket = listener.accept();
try {
clientIP = socket.getLocalAddress().getHostName();
}
catch(Exception e){}
}
}
catch(Exception e){}
}
catch(IOException ex)
{
}
}
}
private void jLabel2MouseClicked(java.awt.event.MouseEvent evt) {
PrintWriter out;
try {
out = new PrintWriter(socket.getOutputStream(), true);
out.println("pc2");
} catch (IOException ex) {
Logger.getLogger(third_frame.class.getName()).log(Level.SEVERE, null, ex);
}
}
//client code
void connect_server()
{
try {
// TODO code application logic here
String serverAddress = JOptionPane.showInputDialog(
"Enter IP Address of a machine that is\n" +
"running the date service on port 9090:");
s = new Socket(serverAddress, 7700);
BufferedReader input =
new BufferedReader(new InputStreamReader(s.getInputStream()));
String answer = input.readLine();
System.out.println(answer);
answer = null;
}
catch (IOException ex) {
Logger.getLogger(client_form.class.getName()).log(Level.SEVERE, null, ex);
}
}
NOTE: Socket is declared globally in both Server and Client.
Client code doesnt have a loop.
On String answer = input.readLine(); the client waits for the message to receive. Once it receives the text from server the clients execution is done.
Client is not written to receive all the message from server.
So if you look back the Server-Client paradigm, the server listens to the port actively and once the client requests something from server. It process the request.
On the other hand , Client doesnt have to listen actively on whats going on at the server which contradicts the fundamental idea of why Client exist.
I have written a small Client/Server Program which already worked once but after adding Threads and some real input Data to it, i always get a closed Socket before being able to read the Object (the String). The Program always Prints "Client has already closed Connection!" from Function handleConnection in the ProcessDataThread.
ClientCode:
synchronized private static void sendToServer(){
Socket clientSocket = null;
BufferedOutputStream socketOut = null;
ObjectOutputStream out = null;
try{
String xmlToSend = "<startTag>\n<someOtherTag id=\"5555\">\n12345\n</someOtherTag>\n</startTag>\n";
Log.d(TAG, "Trying to send the following to the Server:" + xmlToSend);
//TODO load these from file
clientSocket = new Socket( "10.0.2.2", 7777);
socketOut = new BufferedOutputStream(clientSocket.getOutputStream());
out = new ObjectOutputStream(socketOut);
out.writeObject(xmlToSend);
out.flush();
}catch(Exception ex){
Log.e(TAG, "Could not write File to Server.", ex);
}
finally{
try{
if(clientSocket != null){
clientSocket.close();
}
if(out != null){
out.close();
}
}catch(IOException ex){
Log.e(TAG, "Could not close Socket.");
}
}
}
ServerCode:
ReceiverThread:
public void run()
{
try {
ServerSocket server = new ServerSocket(port);
//Only block for 10 Seconds and try again
server.setSoTimeout(10000);
while(!server.isClosed() && !stopped){
//Run
Socket client = null;
try
{
client = server.accept();
System.out.println("Accepted ClientConnection from " + client.getRemoteSocketAddress());
new ProcessDataThread(client).start();
}
catch( SocketTimeoutException tx){
//nothing
}
catch ( IOException e ) {
e.printStackTrace();
}
finally {
if ( client != null )
try { client.close(); } catch ( IOException e ) { e.printStackTrace(); }
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
ProcessDataThread:
public class ProcessDataThread extends Thread {
Socket client;
public ProcessDataThread(Socket sock) {
// xmlToProcess = xmlString;
this.client = sock;
}
private String handleConnection() {
BufferedInputStream socketIn = null;
ObjectInputStream in = null;
String xmlToProcess = null;
try {
if(!client.isClosed()){
System.out.println("Trying to read from Stream;");
socketIn = new BufferedInputStream(client.getInputStream());
in = new ObjectInputStream(socketIn);
Object xmlString = in.readObject();
System.out.println("Read some Object from Stream:" + xmlString.toString());
if (xmlString instanceof String) {
xmlToProcess = (String) xmlString;
System.out.println("Received the following XML:\n" + xmlToProcess);
}
}else{
System.out.println("Client has already closed Connection!");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (EOFException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (socketIn != null) {
socketIn.close();
}
if(client != null){
client.close();
}
} catch (IOException ioex) {
ioex.printStackTrace();
}
}
return xmlToProcess;
}
#Override
public void run() {
String xmlToProcess = handleConnection();
if (xmlToProcess == null || xmlToProcess.isEmpty()) {
// Es konnte kein String vom Client gelesen werden.
return;
}
System.out.println(xmlToProcess);
}
}
I made some changes with jboi's Suggestions. This is what i got now. The error stays the same. I don't even get to reading the Stream in the Server because client.getClosed()
is always true!
In the Client Code:
clientSocket = new Socket( "10.0.2.2", 7777);
clientSocket.setTcpNoDelay(true);
socketOut = new BufferedOutputStream(clientSocket.getOutputStream());
out = new ObjectOutputStream(socketOut);
out.writeObject(xmlToSend);
out.flush();
socketOut.flush();
//Close Output on Socket to signalize the Server that we finished writing!
clientSocket.shutdownOutput();
in = clientSocket.getInputStream();
byte[] receivedData = new byte[8192];
while(in.read(receivedData) != -1) {
//Wait for the Server to Close the Connection
}
In the Server Code
socketIn = new BufferedInputStream(client.getInputStream());
in = new ObjectInputStream(socketIn);
Object xmlString = in.readObject();
System.out.println("Read some Object from Stream:" + xmlString.toString());
if (xmlString instanceof String) {
xmlToProcess = (String) xmlString;
System.out.println("Received the following XML:\n" + xmlToProcess);
}
out = client.getOutputStream();
out.write(1);
//Signalize the Client that we have read everything
client.shutdownOutput();
It is very probable that your client has closed the socket in the finally block before the server was able to read the data.
In your clients finally block you should use socket.shutdownOutput, then read on the client all incoming data till EOF and then close the socket.
On your server you read till EOF and then send an object as kind of acknowledge, e.g. Number of bytes in the message. You also end the send with socket.shutdownOutput() as you've done at the client. This puts again an EOF at the end of the data. This EOF is received by the client and it will finally close the socket.
The issue seems to be the client and server are unable to identify each others state:
Client sending data to server, where server has closed the connection
Server sending/reading data to client , where client has closed the connection
Either are unable to coordinate with each other, solutions could be to establish a proper state machine. Some examples in Google if you search for (client and server state machine) gives mathematically definite state machine examples for your application: hope this comment helps.
Hence it's not useful to look into this problem in solution perspective and probably start using protocols in place like : telnet etc .
Ok now i'm feeling stupid.
I closed the Socket inside the Server Code myself.
After accepting a connection the following is executed inside the finally Block:
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
The reason that there is this finally Block was because i didn't use Threads before so the ReceiverThread also did handle the Connection and therefore close the socket after using it.
I then moved the code to the new Thread and forgot to remove that finally block!
You can't use a buffered input stream and another kind of stream on the same socket. The buffered stream will steal data from the other one. Make up your mind. The ObjectInputStream will do everything you need. Just use that.
EDIT Re your edit, 'socket closed' means that you closed your socket and then continued to use it.
I am trying to write a client-server system using Sockets in java, however I cannot seem to read data sent from the server to the client.
Here is the code for the client:
public class ClientSocket
{
Socket clientSocket = null;
PrintWriter out = null;
BufferedReader in = null;
// establish a connection to All Care's server application through socket 4444 (adjust localhost to reflect the IP address that the server
// is being run from)
public ClientSocket()
{
try
{
clientSocket = new Socket("localhost", 4445);
out = new PrintWriter(clientSocket.getOutputStream());
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
}
catch (IOException e)
{
System.out.println("Could not connect to All Care Server Application");
}
}
public void closeClientSocket()
{
try
{
clientSocket.close();
}
catch (IOException e)
{
System.out.println("Could not close connection to All Care Server Application");
}
}
public String getMessageFromServer()
{
try
{
String input = in.readLine();
return input;
}
catch (IOException e)
{
System.out.println("Could not read message from server");
}
return "No Data";
}
public void sendMessageToServer(String message)
{
out.write(message);
}
}
And here is the Server code:
public class ArFileServer {
public static void main(String[] args)
{
ServerSocket serverSocket = null;
boolean listening = true;
try
{
serverSocket = new ServerSocket(4445);
// infinite loop to continually listen for connection requests made by clients
while (listening)
{
new ClientConnection(serverSocket.accept()).start();
if (serverSocket != null)
{
System.out.println("Connection to client established");
}
}
serverSocket.close();
}
catch (IOException e)
{
System.out.println("Error could not create socket connection to port");
}
}
}
public class ClientConnection extends Thread
{
private Socket socket = null;
public ClientConnection(Socket socket)
{
super("ClientConnection");
this.socket = socket;
}
// the thread that runs after a connection to the server has been accepted
#Override
public void run()
{
try
{
PrintWriter out = new PrintWriter(socket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
sendMessagetoClient(out, "CONNECTION SUCCESS");
// check login credentials sent from client to the server
// if valid send back their encrypted password, otherwise output a login error message
// wait for user input and then do various processes based on their requests
in.close();
out.close();
socket.close();
}
catch (IOException e)
{
System.out.println("Client socket connection error");
}
}
// sends a message to the client
void sendMessagetoClient(PrintWriter out, String message)
{
out.write(message);
}
// listens for a message from the client
String getMessageFromClient(BufferedReader in)
{
try
{
String input = in.readLine();
return input;
}
catch (IOException e)
{
System.out.println("Could not read message from client");
}
return "No Data";
}
And here is the line of code im using to see if the data is being sent.
System.out.println(clientSocket.getMessageFromServer());
In your sendMessageToClient() method, you need to flush:
void sendMessagetoClient(PrintWriter out, String message)
{
out.write(message);
out.flush();
}
Or, when you create the PrintWriter, use the constructor with autoflush:
PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
And when you write, instead of out.write(message) use printf() or println().
There are several problems here.
You are reading lines but you aren't writing lines.
You aren't checking the result of readLine() for null, which means the peer has closed the connection, which means you must do likewise.
You aren't flushing the PrintWriter after you write.
You are closing things in the wrong order. You must close the output writer/stream you have attached to the socket. Doing that flushes it and then closes the input stream/reader and the socket. Doing this in the wrong order loses the flush. Once you've closed the output you don't need the other two closes.
You are using PrintWriter, which swallows exceptions, across a network, where you need to know about exceptions and errors in communication, and you aren't checking for errors either. Use a BufferedWriter.
in the clint code you are not connecting with server socket.
for clint socket connection
socket soc= new socket ("server host ip",port);
I am making a prototype client & server so that I can understand how to handle reconnects.
The server ought to create a serversocket and listen forever. A client may connect, send its data, and close its socket but it will not send a "I'm done and closing" type message to the server. For this reason, the server gets a EOFException when it does a readByte() since the remote client has closed. In the error handler for the EOFException, it will close the socket and open a new one.
Here's the problem: The client sometimes gets a SocketWriteError when it does the outputStream.write() call even after it successfully opens the socket/inputstream/outpustream. It may have something to do with the frequency that I'm opening and closing these sockets. One interesting thing is that the client does an arbitrary number of writes/close/reconnects before crapping out. It will sometimes crap out on the first reconnect, other times it will take 50 reconnects before seeing the SocketWriteError.
Here's the error on the client side:
java.net.SocketException: Connection reset by peer: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
at java.net.SocketOutputStream.write(SocketOutputStream.java:115)
at bytebuffertest.Client.main(Client.java:37)
Here are some snippets of code:
SERVER:
public static void main(String[] args)
{
Server x = new Server();
x.initialize();
}
private void initialize()
{
ServerSocket s;
InputStream is;
DataInputStream dis;
while (true) //ADDED THIS!!!!!!!!!!!!!!!!!!!!!!
{
try
{
s = new ServerSocket(4448);
s.setSoTimeout(0);
s.setReuseAddress(true);
is = s.accept().getInputStream();
System.out.println("accepted client");
dis = new DataInputStream(is);
try
{
byte input = dis.readByte();
System.out.println("read: " + input);
} catch (Exception ex)
{
System.out.println("Exception");
dis.close();
is.close();
s.close();
}
} catch (IOException ex)
{
System.out.println("ioexception");
}
}
}
CLIENT:
public static void main(String[] args)
{
Socket s;
OutputStream os;
try
{
s = new Socket("localhost", 4448);
s.setKeepAlive(true);
s.setReuseAddress(true);
os = s.getOutputStream();
int counter = 0;
while (true)
{
try
{
os.write((byte) counter++);
os.flush();
os.close();
s.close();
s = new Socket("localhost", 4448);
s.setKeepAlive(true);
s.setReuseAddress(true);
os = s.getOutputStream();
} catch (Exception e)
{
e.printStackTrace();
System.err.println("ERROR: reconnecting...");
}
}
} catch (Exception ex)
{
ex.printStackTrace();
System.err.println("ERROR: could not connect");
}
}
Does anyone know how to properly reconnect?
Don't close the ServerSocket on an error, just .accept() a new connection.
What I normally do is each time ServerSocket.accept() returns a Socket, I spawn off a thread to handle sending and receiving from that Socket. That way you're ready to start accepting a new connection as soon as somebody wants to connect to you.