I'm kind of stuck on one issue. I got a client-server app in Java, where multiple clients can connect to a server. Now I have a cyclic operation, which is getting the current time (corresponding to my ClockTask on the server side). But I don't really know how do I transmit this time data to all connected clients. It should be done somehow by ObjectOutputStream I guess, but it would be nice if someone could clue me in.
Here's my server code, together with thread running a client connection:
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean listeningSocket = true;
try {
serverSocket = new ServerSocket(11111);
} catch (IOException e) {
System.err.println("Could not listen on port: 11111");
}
while(listeningSocket){
System.out.println("Waiting for a client to connect...");
Socket clientSocket = serverSocket.accept();
System.out.println("Client connected!");
ConnectThread ct = new ConnectThread(clientSocket);
ct.start();
}
serverSocket.close();
}
}
Connect thread:
public class ConnectThread extends Thread{
private Socket socket = null;
public ConnectThread(Socket socket) {
super("ConnectThread");
this.socket = socket;
}
#Override
public void run(){
ObjectOutputStream serverOutputStream = null;
ObjectInputStream serverInputStream = null;
try {
System.out.println("check");
serverOutputStream = new ObjectOutputStream(socket.getOutputStream());
System.out.println("check");
serverInputStream = new ObjectInputStream(socket.getInputStream());
serverOutputStream.writeInt(42);
System.out.println("check");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
try {
serverOutputStream.close();
serverInputStream.close();
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
and the client:
public class Client {
public static void main(String[] arg) {
Socket socketConnection = null;
ObjectOutputStream clientOutputStream = null;
ObjectInputStream clientInputStream = null;
try {
socketConnection = new Socket("127.0.0.1", 11111);
clientOutputStream = new ObjectOutputStream(
socketConnection.getOutputStream());
clientInputStream = new ObjectInputStream(
socketConnection.getInputStream());
System.out.println("check");
System.out.println(clientInputStream.readInt()); // HERE'S WHERE THE EXCEPTION OCCURS
} catch (Exception e) {
System.out.println("The following exception has occured and was caught:");
System.out.println(e);
}
finally{
try {
clientOutputStream.close();
clientInputStream.close();
socketConnection.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Clock task:
public class ClockTask extends TimerTask {
#Override
public void run() {
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
Calendar c = Calendar.getInstance();
System.out.println(dateFormat.format(c.getTime()));
//some object output stream here??
}
}
I don't suggest sending a Calendar object as it is a very expensive object using around 2900 bytes. Instead you could send a long value over a DataOutputStream which would use 8 bytes.
Note: you would need to correct for the latency between the client and the server otherwise the time will be always delayed.
A simple way to address this is for the client to send a message to the server with a timestamp as long, the server responds with it's own time stamp and you can assume that the delay is half the round trip time. You can then apply an EWMA (Exponentially Weighted Moving Average) to get a reason average of the difference in the clock on the server and the client.
Related
I'm developing a client server application in java. Communication takes place by serializing/deserializing immuable objects containing the information required, with ObjectOutputStream and ObjectInputStream.
In the server, every time I accept a new tcp connection, I instantiate a new Thread to handle the connection with that particular client.
This thread has a reference to the socket and it keeps reading objects:
while (true){
Object receivedObject = inputStream.readObject();
if (receivedObject instanceof MessageA){
//do sth
} else if (receivedObject instanceof MessageB){
//do sth else
}
this Runnable also has a method to send objects to the client:
public void sendMessage(Message message) {
try {
output.writeObject(message);
output.reset();
} catch (IOException e) {
e.printStackTrace();
}
}
client-side, when the user enters the server's address, I instantiate a SocketClient object to handle the communication with the server:
public class SocketClient extends Observable {
private final Socket socket;
private final ObjectOutputStream outputStream;
private final ObjectInputStream inputStream;
private static int TIMEOUT = 5000;
public SocketClient(String serverAddress, int serverPort) throws IOException {
this.socket = new Socket();
this.socket.connect(new InetSocketAddress(serverAddress, serverPort), TIMEOUT);
this.outputStream = new ObjectOutputStream(socket.getOutputStream());
this.inputStream = new ObjectInputStream(socket.getInputStream());
}
public void readMessage() {
Thread readerThread = new Thread(() -> {
boolean read = true;
while (read) {
Message message;
try {
message = (Message) inputStream.readObject();
notifyObservers(message);
} catch (IOException | ClassNotFoundException e) {
message = new ErrorMessage(null, "Connection lost with the server.");
disconnect();
read = false;
}
}
});
readerThread.start();
}
public void sendMessage(Message message) {
try {
outputStream.writeObject(message);
outputStream.reset();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void disconnect() {
try {
socket.close();
} catch (IOException e) {
// disconnection error
e.printStackTrace();
}
}
}
messages are sent and received in both applications, the only problem is that when I send multiple messages sequentially in the server, they are sometimes received in a different order in the clients.
How may I fix that?
I'm trying to make a connection between a server and multiple clients, but it doesn't work even for one. All I want to do is to send from the client an object using the ObjectOutputStream class. The connection is made successfully at the beginning but when I try to send the object to the server it fails.
This is the client part which is written in the main method of a class:
Socket socket;
OutputStream out;
ObjectOutputStream fout;
boolean connected=false;
if (!connected) {
try {
socket = new Socket("localhost", 8000);
out = socket.getOutputStream();
fout = new ObjectOutputStream(out);
fout.flush();
connected = true;
fout.writeObject(ac1);//ac is an object of Plane class
} catch (Exception ex) {
System.out.println(ex.toString());
}
}
This is the server:
public class server {
static class ServerThread implements Runnable {
Socket client = null;
public ServerThread(Socket c) {
this.client = c;
}
public void run() {
try {
System.out.println("Connected to client : "+client.getInetAddress().getHostName());
Plane ac=null;
InputStream in=client.getInputStream();
ObjectInputStream fin=new ObjectInputStream(in);
while(client.isConnected()){
ac = (Plane)fin.readObject();
System.out.println(ac.toString());
}
client.close();
} catch (Exception e) {
// System.err.println(e.getMessage());
e.printStackTrace();
}
}
}
public static void main(String args[]) {
try {
ServerSocket server = new ServerSocket(8000);
while (true) {
Socket p = server.accept();
new Thread(new ServerThread(p)).start();
}
} catch (Exception ex) {
System.err.println("Error : " + ex.getMessage());
}
}
}
Could anyone tell me what is the problem?
Your client never closes the socket, and presumably exits, so the connection is reset. So close the socket.
NB isConnected() is not a valid loop condition. It will never become false. Your loop should terminate when EOFExceprion is caught.
I got to stage where client and server communicate, sending messages from and to each other.
The problem I am having is how to close the connection without causing an error?
If I terminate one of the apps (either server or client) that causes the connection to be lost, and then it causes the loop that is waiting for input to loop indefinitely and showing null's.
I tried closing sockets, buffers and even the thread, didn't work.
This is the client side
public void onClick(View view) {
try {
EditText et = (EditText) findViewById(R.id.EditText01);
String str = et.getText().toString();
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
out.println(str);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
class ClientThread implements Runnable {
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
CommunicationThread commThread = new CommunicationThread(socket);
new Thread(commThread).start();
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
This is the server side
class ServerThread implements Runnable {
public void run() {
Socket socket = null;
try {
serverSocket = new ServerSocket(SERVERPORT);
} catch (IOException e) {
e.printStackTrace();
}
while (!Thread.currentThread().isInterrupted()) {
try {
socket = serverSocket.accept();
CommunicationThread commThread = new CommunicationThread(
socket);
new Thread(commThread).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Both use these classes:
class CommunicationThread implements Runnable {
private Socket clientSocket;
private BufferedReader input;
public CommunicationThread(Socket clientSocket) {
this.clientSocket = clientSocket;
try {
this.input = new BufferedReader(new InputStreamReader(
this.clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
String read = input.readLine();
updateConversationHandler.post(new updateUIThread(read));
//***HERE EXTRA BIT FOR THE SERVER
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class updateUIThread implements Runnable {
private String msg;
public updateUIThread(String str) {
this.msg = str;
}
#Override
public void run() {
text.setText(msg);
}
}
the only difference is the server has this bit where it says above ***HERE EXTRA BIT FOR THE SERVER
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
out.println("Message recieved");
so basically, client connects, server accepts, then client sends message, servers receives message and shows it, and then sends "Message received" to the client, and the client shows it.
All this works fine, but once the connection is lost, they hang on showing null repeatedly, and I have to force the app to close.
You aren't checking for end of stream. If readLine() returns null, the peer has closed the connection, and you must do likewise and stop reading.
It's hard to believe you really need a new thread for every line to update the UI.
Trying to send an arrayList over a socket, get a null pointer exception at object input stream initialization (client).
Client:
try {
ObjectInputStream objIn = new ObjectInputStream(
Client.socket.getInputStream()); // HERE
library = (ArrayList<Book>) objIn.readObject();
} catch (IOException e) {
Server:
try {
ObjectOutputStream objOut = new ObjectOutputStream(
this.client.getOutputStream());
objOut.writeObject(library);
objOut.flush(); // added later, not helping
}
I've been trying to comunicate over sockets for two days now with almost no success. I have no idea what's going on. Ofc I plan to document myself better when I'll have more time but for now I'd really like to understand what is happening.
EDIT
public class Client {
private static int port = 6666;
private static Socket socket = null;
public Client (int port) {
Client.port = port;
}
public Client () {
}
public void establishConnection() {
try {
Client.socket = new Socket(InetAddress.getByName(null), Client.port);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Server:
public void start () {
(new Thread() {
public void run() {
try {
Server.socket = new ServerSocket(Server.portNumber);
while (!Server.stop) {
Socket client = Server.socket.accept();
(new HandleRequest (client)).start();
}
...............
public class HandleRequest extends Thread {
private Socket client = null;
private SQL sql_db = new SQL ();
public HandleRequest (Socket client) {
this.client = client;
}
#Override
public void run () {
try {
if (!this.sql_db.isConnected())
this.sql_db.connect();
if (this.client == null) {
System.out.println("Error: client does not exist, NO idea what's going on");
return;
}
ArrayList<Book> library = this.sql_db.getAllBooks();
try {
ObjectOutputStream objOut = new ObjectOutputStream(
this.client.getOutputStream());
objOut.writeObject(library);
objOut.flush();
} catch (Exception e) {
System.out.println("Server error in handling request for whole library!");
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Because the NPE is on this line:
Client.socket.getInputStream());
there is only one thing that can cause it. It can't be Client, because that is static. It can't be getInputStream(), because that is a method, so it has to be socket that is causing the NPE.
On this line:
private static Socket socket = null;
you set socket to be null. The only place I see where you set it to be not null is in your .establishConnection() method, but I don't see where you call that method.
Therefore, your problem is most likely that you aren't calling the .establishConnection() method.
Is you establishConnection method called before
try {
ObjectInputStream objIn = new ObjectInputStream(
Client.socket.getInputStream()); // HERE
library = (ArrayList<Book>) objIn.readObject();
} catch (IOException e) {
If not, your Client.socket is null and you need to initialize it. I.e. your code should look like this:
try {
Client c = new Client(1337);
c.establishConnection();
ObjectInputStream objIn = new ObjectInputStream(
c.socket.getInputStream()); // HERE
library = (ArrayList<Book>) objIn.readObject();
} catch (IOException e) {
I am trying to write a program in which the client requests the number of cores the server has. I do this as follows:
Client:
public void actionPerformed(ActionEvent e) {
try {
Socket clientSocket = new Socket("128.59.65.200", 6789);
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String numberOfCores = inFromServer.readLine();clientSocket.close();
System.out.println(numberOfCores);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
Server:
public static void sendNumberOfCores() {
Thread coresThread = new Thread() {
public void run() {
try {
int numberOfCores;
ServerSocket welcomeSocket = new ServerSocket(6789);
while (true) {
Socket connectionSocket = welcomeSocket.accept();
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
numberOfCores = Runtime.getRuntime().availableProcessors();
outToClient.write(numberOfCores);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
coresThread.setName("Wait for core request thread");
coresThread.start();
}
However, when I load the server and hit the button on my gui which runs the client code, nothing happens and the button just gets stuck. What is causing this?
Thank you.
Server not initialized on the 6789 port and make sure you do that in a separate thread.
Some thing like this.
In Server class:
--Make an inner class say MyServer
class MyServer implements Runnable{
final int BACKLOG=10; //10 is the backlog,if your server wishes to serve requests.
final int PORT = 6789;
public void run(){
try {
ServerSocket serverSocket = new ServerSocket(PORT,BACKLOG); //10 is the backlog,if your server wishes to serve conncurrent requests.
while (true) {
Socket ClientConnetion = serverSocket.accept();
//Now whatever you want to do with ClientConnection socket you can call
}
} catch (Exception e) {
e.printStackTrace();
}
}
--Start this thread in you main server class
MyServer mys=new MyServer();
Thread r=new Thread(mys);
mys.start();
It ended up that I was sending an integer when the code on the client was waiting for a string.