I have many clients that are waiting for server messages. So the client make accept() and wait for server. When server have messages, open a connection to the client and send messages, after that, close the communication and the cycle restart.
I've seen usually the inverse approach, where the server do accept() and client connect to it. I've wrote this code but the client (that do accept() ) is blocked on point 3 and the server (that create the connection to the client) is blocked on point 2.
Sure i have some problems in my code (dont know where), but... this is the correct way ?
The client (that do accept() and wait for new messages)
try {
System.out.println("Waiting..");
receiver = serverSocket.accept();
System.out.println("1");
ObjectInput fromServerReader = new ObjectInputStream(receiver.getInputStream());
ObjectOutputStream toServerWriter = new ObjectOutputStream(receiver.getOutputStream());
System.out.println("2");
toServerWriter.writeObject("dummy");
toServerWriter.flush();
System.out.println("3");
ScheduledEvent scheduledEvent = (ScheduledEvent) fromServerReader.readObject();
System.out.println("4");
receiver.close();
System.out.println("5");
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// Should never happen
}
The server (that when have new message to send to client, create the
connection)
try {
InetAddress address = InetAddress.getByName(sendToUser
.getMachineName());
socket = new Socket(address, port);
log.debug("1");
ObjectOutputStream toClientWriter = new ObjectOutputStream(
socket.getOutputStream());
ObjectInputStream fromClientReader = new ObjectInputStream(socket.getInputStream());
log.debug("2");
String read = (String)fromClientReader.readObject();
log.debug("3");
// Compose the message
ScheduledEvent scheduledEvent = new ScheduledEvent();
scheduledEvent.setSubject(event.getSubject());
scheduledEvent.setMessage(event.getText());
log.debug("4");
toClientWriter.writeObject(scheduledEvent);
toClientWriter.flush();
log.debug("5");
socket.close();
log.debug("6");
} catch (UnknownHostException e) {
// TODO handle
e.printStackTrace();
} catch (IOException | ClassNotFoundException e) {
// TODO handle
e.printStackTrace();
}
In client code, instead of using
PrintWriter writer;
Use
ObjectOutputStream writer;
And then use
writer.writeObject("dummy");
writer.flush();
Try using println instead of write toServerWriter.println("dummy");. The server may be waiting for the newline character.
Related
I have established a connection via sockets between two computers. I have created an own object called "Result" and I can successfully transfer it to the server computer from the client computer.
If I do this socket connection only on my computer then I can receive an object from the server computer as well.
The problem is when I try to receive an object from the server computer. I get error messages and I have the feeling that something is happening to my object that is being sent. If I open a saved (serializable) Result object on my own computer in notepad then I get a lot of random symbols but when I do the same on the server computer then it is only two symbols.
Here is my code, I'm using JFileChooser so I can easily access the object I want to send from the server, understandably I have access to both computers.
Code for the sending server
public static void serverSendObject() throws IOException, ClassNotFoundException {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(2001,10);
}
catch (IOException ex) {
System.out.println("Can't setup server on this port
number. ");
}
Socket socket = null;
OutputStream out = null;
ObjectOutputStream objOut = null;
try {
socket = serverSocket.accept();
}
catch (IOException ex) {
System.out.println("Can't accept client connection. ");
}
try {
out = socket.getOutputStream();
}
catch (IOException ex) {
System.out.println("Can't get socket input stream. ");
}
try {
objOut = new ObjectOutputStream(out);
}
catch (FileNotFoundException ex) {
System.out.println("File not found. ");
}
JFileChooser fc = new JFileChooser();
int reValue=fc.showOpenDialog(null);
if(reValue == JFileChooser.APPROVE_OPTION) {
try(ObjectInputStream objInput = new ObjectInputStream(new FileInputStream(fc.getSelectedFile()))) {
objOut.writeObject(objInput.readObject());
}
catch(IOException e) {
}
catch(ClassNotFoundException e) {
}
}
serverSocket.close();
socket.close();
}
Code for the receiving client
public void loadExternal() throws IOException, ClassNotFoundException {
Visualizer vis = new Visualizer();
currentVis=vis;
Socket socket = null;
String host= *insert IP address*
socket= new Socket(host, 2001);
InputStream in = socket.getInputStream();
ObjectInputStream objIn = new ObjectInputStream (in);
currentRes = (Result) objIn.readObject();
objIn.close();
socket.close();
}
I keep getting
java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(Unknown Source)
as an error. I have tried to put a catch on this but it doesn't help. I have tried some different methods but nothing seems to work.
Just want to point out that the exact same code works when I connect the sockets on my OWN computer and that this problem occurs when I connect two different computers AND that I'm being able to send an object to the server computer.
EDIT: I think I can confirm that something has happaned to the object I have sent. A locally (via sockets) saved object is 1131 bytes while the object I have sent to the server computer is only 4 bytes.
I use the same kind of technique when I send the objects, with ObjectOutputStream at the client and ObjectInputStream at the server.
whenever you write anything. remember to flush and then close. Hope can help.
I am writing HTTP WEB SERVER code. In the mean while I have to code retry policy on using port, so that on that port server can listen client's request.
Normal Code:
serversocket = new ServerSocket(ServerSettings.port);
It throws Exception, if ServerSettings.port is not free.
Now, I want to add retry policy, if ServerSettings.port is not free, try other ports. For that I write one code, and code is a s follows,
Updated Code:
try {
serversocket = new ServerSocket(ServerSettings.port);
} catch (IOException io) {
try {
ServerSettings.port += 505;
serversocket = new ServerSocket(ServerSettings.port);
} catch (IOException io1) {
try {
ServerSettings.port += 505;
serversocket = new ServerSocket(ServerSettings.port);
} catch (IOException io2) {
log.info(new Date() + "Problem occurs in binding port");
}
}
}
But above one shows poor coding skills, and not professional one.
How can I write retry policy for ports in a professional way, so that server can listen on that port?
Logically, I think this will work (Correct me if there are any syntax typos):
ServerSocket serversocket;
boolean foundPort = false;
while (!foundPort)
{
try {
serversocket = new ServerSocket(ServerSettings.port); // If this fails, it will jump to the `catch` block, without executing the next line
foundPort = true;
}
catch (IOException io) {
ServerSettings.port += 505;
}
}
You could wrap it in a function, and instead of foundPort = true;, you would return the socket object.
So the end result of my program is an updating game client, but what i have so far is a server that is able to accept multiple connections, and a client that connects to the server. this is the code for the client portion:
public void client() {
Socket socket = null;
ObjectInputStream in = null;
ObjectOutputStream out = null;
try {
socket = new Socket(IP, Integer.parseInt(port));
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
do {
// have a conversation
try {
message = (String) in.readObject();
System.out.println("\n" + message);
} catch (Exception e) {
System.out.println("\n idk wtf that user sent!");
}
} while (!message.equals("CLIENT - END")); // When the user types "END"
System.err.println("CLOSED!!!");
System.exit(0);
}
and this is the code for the server portion:
public void run() {
// where everything happens
System.out.println("server- connected");
try {
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject("hi");
out.flush();
Thread.sleep(5000);
out.writeObject("close");
out.flush();
System.out.println("closed");
} catch (Exception e) {
e.printStackTrace();
}
}
now, i am running into this problem where, when my server sends the object "hi" the client appears to not receive it. i'm not totally sure if it does, but if it is getting it, it isnt printing it out like i wanted. i previously have made a chat program that does this same thing, and i pretty much copied it to this, but it isnt communicating. the most i get is the confirmation that they are connected. im not sure what is going on, but any help would be appreciated! thanks in advance!
create the ObjectOutputStreams before the ObjectInputStreams and flush them immediately after creation.
the constructor of an ObjectInputStream reads the stream header. this stream header is written by the constructor of the ObjectOutputStream (kind of an ugly implementation, but it is what it is). if you construct the OIS's first, they hang waiting for the header bytes.
i'm learning java and i faced some problems with sockets. I developed a simple client-server app - kind of knock-knock, it performs 4 steps:
client sends some message to server
server recieves them and saves to file
server sends back to client some other messages
client recieves them and also saves to file
Problem appears on step #4: client doesn't recieve messages and never gets out the loop:
while ((inStr = in.readLine()) != null) {
writer.println(inStr);
}
where in is type of BufferedReader:
try {
socket = new Socket(ipAddress, 4444);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
On server side messages are sent:
try {
socket = srvSocket.accept();
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
...
out.println("test from server #1");
out.println("test from server #2");
on client side i watched in.ready() - it returns false. On server side i watch out.checkError() - it returns true;
What am i doing wrong - why is the stream empty ?
Any help ia appreciated! :)
You are using public PrintWriter(OutputStream out, boolean autoFlush) which will flush automatically on new line or println. It does not autoflush after every write. You have to flush after every write.
Here is javadoc for the autoFlush param of the constructor:
A boolean; if true, the println, printf, or format methods will flush the output buffer
This might/might not solve your problem. But try keeping everything within Try Catch block. For eg: your ServerSocket initialization, writer blocks etc. If some error occurs, you might not be able to use writer anyhow, so there is no point in initializing it.
You might try writing to standard output stream for debugging instead of a file. Below code for Server/ Client is a minor variant of yours and its working.
Server:
Socket socket;
ServerSocket srvSocket;
BufferedReader in;
PrintWriter out;
try {
srvSocket=new ServerSocket(4444);
socket = srvSocket.accept();
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out.println("test from server #1");
out.println("test from server #2");
} catch (IOException e) {
e.printStackTrace();
}
Client
Socket socket;
BufferedReader in;
PrintWriter out;
String inStr;
try {
socket = new Socket("127.0.0.1", 4444);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while ((inStr = in.readLine()) != null) {
System.out.println(inStr);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
I have a server in Java which listens for incoming connection to a specific port. And everything works as expected, my clients connect to the server and I'm able to send data between them.
My problem is that, when I shut down my client, turn it on again and try to reconnect, it won't connect (my server stays on all the time).
For me to reconnect, I have to restart my server again.
So I tried doing this on my server side:
InetSocketAddress serverAddr = new InetSocketAddress(serverIpAddress, serverPort);
serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true);
//I tries setting up a reuse option
serverSocket.bind(serverAddr);
Even after setReuseAddress() my client won't connect unless I restart my server!
Has anyone any idea of how could that be done?
EDIT2:
try {
while(true){
clientSocket = serverSocket.accept();
System.out.println("S-a conectat clientul de monitorizare!");
os=new ObjectOutputStream(clientSocket.getOutputStream());
try{
coord=(Coordinate)queue.take();
System.out.println(coord.getLat()+coord.getLon()+coord.getVit()+coord.getwId()+coord.getime());
os.writeObject(coord);
os.flush();
}
catch(Exception e)
{
e.printStackTrace();
}
}
} catch (IOException e) {
System.out.println(e);
try {
clientSocket.close();
os.close();
}catch(Exception e1) {
e1.printStackTrace();
}
}
New edit:
Thread pool server:
Main:
ThreadPooledServer server = new ThreadPooledServer(queue,7001);
new Thread(server).start();
ThreadPooledServer:
public class ThreadPooledServer implements Runnable {
protected ExecutorService threadPool =
Executors.newFixedThreadPool(5);
public void run() {
openServerSocket();
while (!isStopped()) {
Socket clientSocket = null;
try {
System.out.println("Serverul asteapta clienti spre conectare");
clientSocket = this.serverSocket.accept();
clientconnection++;
System.out.println("Serverul a acceptat clientul cu numarul:"
+ clientconnection);
} catch (IOException e) {
if (isStopped()) {
System.out.println("Server Stopped.");
return;
}
throw new RuntimeException("Error accepting client connection",
e);
}
WorkerRunnable workerRunnable = new WorkerRunnable(queue,clientSocket);
this.threadPool.execute(workerRunnable);
}
System.out.println("Server Stopped.");
}
public synchronized void stop() {
this.isStopped = true;
try {
this.threadPool.shutdown();
}
catch (IOException e) {
throw new RuntimeException("Error closing server", e);
}
}
private void openServerSocket() {
try {
InetSocketAddress serverAddr = new InetSocketAddress(SERVERIP,
serverPort);
serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(serverAddr);
} catch (IOException e) {
throw new RuntimeException("Cannot open port", e);
}
}
this.serverSocket.close();
In your run method you accept one client and then go in to an endless loop, trying to write data to the ObjectOutputStream. When the client closes the connection an exception is thrown because you can no longer write to the stream. At this point we're out of the endless loop(while(true) { .. }) and the run method ends.
If you want to keep accepting clients I suggest you move the while loop to the top of your code, above the accept to be exact.
Pseudo-ish code below(note: I'm not catching any exceptions etc.):
while (true)
{
// Wait for a client to connect..
Socket clientSocket = serverSocket.accept();
// Write to the client..
ObjectOutputStream os = new ObjectOutputStream(clientSocket.getOutputStream());
os.writeObject(coord);
os.flush();
}
Is your server single threaded for a purpose (do you only accept one client at a time) ? Usually, servers will spawn a separate thread for every connections, so it can listen more often for incoming connections, and so if the client's connection throws any errors, it won't affect the listening socket. At the moment, your server will listen to only one connection, and if an exception occurs handling the client's connection, simply move on and never listen again. In pseudocode, a typical server is like :
Server listening thread (main thread)
try {
create server socket and bind to port
while server is online
listen for incoming connections
if the client connection is accepted [1]
start client thread
catch exception
handle exception
finally
make sure the server socket is disconnected
cleanup
Server client connection thread
write to client socket to initialize connection
try
while scoket is opened
read data
data treatment
write response
catch exceptions
handle exception [2]
finally
close client socket
cleanup
[1] if your server handles only one client, it should refuse the connection, so the client doesn't wait for no reason
[2] if the exception is not about the socket, the client should be warned by a final write to the socket before closing it
Client thread (on the client's side)
try
connect to server
protocol handshake (optional) [4]
while socket is connected
client server communication
catch exception
handle excpetion
finally
close socket
[4] since the server should write to the socket first, the client should read from it for any welcome message or error messages before attempting to write anything.