AsynchronousServerSocketChannel with graceful shutdown - java

In my previous Question i asked how to implement a correct Multithreaded server. I got the response to program a "graceful shutdown", and i tried todo so. However, it didn't work. I still have open sockets in TIME_WAIT state on the client side.
Client:
private <T extends Serializable> T sendCommand(final Command<T> command) throws ExecutionException, InterruptedException, IOException, ClassNotFoundException {
T result = null;
try (final AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(channelGroup)) {
channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
channel.connect(this.mwInfo.getNextMiddleware()).get();
final OutputStream os = Channels.newOutputStream(channel);
final InputStream is = Channels.newInputStream(channel);
final ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(command);
oos.flush();
channel.shutdownOutput();
final ObjectInputStream ois = new ObjectInputStream(is);
result = (T) ois.readObject();
while(ois.read() != -1){
System.out.println("busy");
}
try{
channel.shutdownInput();
}catch(Exception ex){
ex.printStackTrace();
}
oos.close();
ois.close();
}
return result;
}
Server:
this.asyncSocket.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
#Override
public void completed(final AsynchronousSocketChannel result, Void attachment) {
asyncSocket.accept(null, this);
exec.submit(new Runnable() {
#Override
public void run() {
Command cmd = null;
ObjectInputStream ois = null;
ObjectOutputStream oos = null;
try {
ois = new ObjectInputStream(Channels.newInputStream(result));
cmd = (Command) ois.readObject();
while(ois.read() != -1){
System.out.println("busy");
}
result.shutdownInput();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try{
oos = new ObjectOutputStream(Channels.newOutputStream(result));
oos.writeObject("test"); //do some other work here..
oos.flush();
result.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
}
try {
oos.close();
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
result.close();
}catch (IOException ex){
ex.printStackTrace();
}
}
});
}
#Override
public void failed(Throwable exc, Void attachment) {
}
});
Does anybody know why this isn't a graceful shutdown?
It doesn't look well structured, since i was playing with the try-catch blocks..
Thanks in advance!

I still have open sockets in TIME_WAIT state on the client side.
You will always have sockets in TIME_WAIT on one side or the other, and the client side is where you want them, not the server side.
The state expires after 2*MSL, which means two maximum segment lifetimes, which means two times two minutes.
There is no problem here to solve.

Related

App freezes when trying to send an object via a socket

Let me jump right in. Here's my Server class:
public class DTServer {
ServerSocket serverSocket;
ServerSocketHints serverSocketHints;
Socket socket;
InputStream inputStream;
OutputStream outputStream;
ObjectInputStream objectInputStream;
ObjectOutputStream objectOutputStream;
public DTServer(int port) {
serverSocketHints = new ServerSocketHints();
serverSocketHints.acceptTimeout = 0;
serverSocket = Gdx.net.newServerSocket(
Net.Protocol.TCP, port, serverSocketHints);
socket = serverSocket.accept(null);
}
public Serialized receiveSerialized() {
inputStream = socket.getInputStream();
try {
objectInputStream = new ObjectInputStream(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
outputStream = socket.getOutputStream();
try {
objectOutputStream = new ObjectOutputStream(outputStream);
} catch (IOException e) {
e.printStackTrace();
}
Serialized serialized = new Serialized();
try {
serialized = (Serialized) objectInputStream.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return serialized;
}
}
And the Client class:
public class DTClient {
Socket socket;
SocketHints socketHints;
InputStream inputStream;
OutputStream outputStream;
ObjectInputStream objectInputStream;
ObjectOutputStream objectOutputStream;
public DTClient(String address, int port) {
socketHints = new SocketHints();
socketHints.connectTimeout = 3000;
socketHints.keepAlive = true;
// socketHints.trafficClass = 0x04; //IPTOS_RELIABILITY
socket = Gdx.net.newClientSocket(
Net.Protocol.TCP, address, port, socketHints);
}
public void sendSerialized(Serialized serialized) {
inputStream = socket.getInputStream();
try {
objectInputStream = new ObjectInputStream(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
outputStream = socket.getOutputStream();
try {
objectOutputStream = new ObjectOutputStream(outputStream);
} catch (IOException e) {
e.printStackTrace();
}
try {
objectOutputStream.writeObject(serialized);
} catch (IOException e) {
e.printStackTrace();
}
}
}
I create the server object like this:
public void startServer() {
new Thread(new Runnable() {
#Override
public void run() {
dtServer = new DTServer(32658);
System.out.println("Server started and listening at port: 32658.");
}
}).start();
}
And then connect to it with other instance of the program:
public void connect() {
new Thread(new Runnable() {
#Override
public void run() {
dtClient = new DTClient("127.0.0.1", 32658);
System.out.println("Connected to server at 127.0.0.1:32658");
}
}).start();
}
And everything work swell until I try to receive the object I sent:
game.dtClient.sendSerialized(new Serialized(game.gameScreen.localPlayer));
//client side
Serialized s = (Serialized)game.dtServer.receiveSerialized();
//server side
Calling receiveSerialized method causes both app instances to freeze.
Create the ObjectOutputStream before the ObjectInputStream, at both ends. Otherwise you can get a deadlock trying to read the object stream header.
You should also use the same object streams for the life of the socket, rather than a new pair per message.

Keep communication open between server and client - Java

How do you make a client which is able to send a server multiple messages at anytime, and therefore a server listening for a message all the time.
Right now I have wrote some code which only allows me to send a message once. I thought this was due to me closing the input/output streams and the sockets. So I have been playing around for a while now and I can't seem to do it!
Client:
public class Client {
private Socket socket;
private OutputStream os;
public Client() {}
public void connectToServer(String host, int port) {
try {
socket = new Socket(host, port);
} catch (IOException e) {
e.printStackTrace();
}
sendMessage();
}
public void sendMessage() {
try {
os = socket.getOutputStream();
String string = "Anthony";
byte[] b = string.getBytes(Charset.forName("UTF-8"));
os.write(b);
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void STOP() {
stopOutput();
stopServer();
}
public void stopServer() {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stopOutput() {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Server:
public class ConnectionHandler implements Runnable {
private Socket clientSocket;
private BufferedReader in;
public ConnectionHandler(Socket clientSocket) {
this.clientSocket = clientSocket;
String clientAddress = clientSocket.getInetAddress().toString()
.substring(1);
System.out.println("Connected to " + clientAddress);
try {
in = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
while (true) {
try {
ArrayList<String> data = new ArrayList<String>();
String inputLine;
while ((inputLine = in.readLine()) != null) {
data.add(inputLine);
}
if (data.size() > 0) {
System.out.println(data.toString());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void STOP() {
stopInput();
stopConnection();
}
public void stopInput() {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stopConnection() {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
At the moment on the client side, I send a message as soon as the socket is opened but after when I call the send function from another class it does not send...
How should I do this? Or what am I doing wrong?
Thanks in advance.
p.s. I am guessing client-server is the same as server-client, so if I know how to do one way I can easily switch it around... right?
Turns outs it was a simple error.
I as writing (sending-client) as an OutputStream however I was then reading (receiving-server) as BufferedReader! ha
So quick tip for anyone, make sure you receive messages the same way you send them!
Thanks for everyone who tried helping.
Your server is accepting data all the time, so you just have to save the OutputStream of you Client somewhere and write data to it every now and then. But do not close it, because then you close the Client socket, too.
After you have done that, you would need to change something else, because now your call of in.readLine() blocks your server, because it waits for the client to send something. To prevent that, you could try to add sending a String like "close" to the server when you want to close your client, something like that:
public void STOP() {
os.write("close".getBytes(Charset.forName("UTF-8")));
stopOutput();
stopServer();
}
and change the code in your server to
try {
ArrayList<String> data = new ArrayList<String>();
String inputLine;
while (!(inputLine = in.readLine()).equals("close")) {
data.add(inputLine);
}
if (data.size() > 0) {
System.out.println(data.toString());
}
} catch (IOException e) {
e.printStackTrace();
}

Should I call reset() before close() on an ObjectOutputSream?

I'm taking over an existing JAVA project which containing the following code:
class ConnectionHandler extends Thread {
private Socket socket;
public ConnectionHandler(Socket s) {
this.socket = s;
}
private void doSthForRequest(ObjectInputStream in, ObjectOutputStream out) throws Exception {
// Do something and write output to out:
// out.writeObject(someOutput);
}
public void run() {
ObjectOutputStream out = null;
ObjectInputStream in = null;
try {
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
while (true) {
out.reset();
doSthForRequest(in, out);
}
} catch (Exception ex) {
if (out != null && !socket.isOutputShutdown()) {
try {
out.writeObject(ex);
out.flush();
} catch (Exception ex2) {}
}
} finally {
if (out != null) {
try {
out.reset(); // any reason for this?
} catch (Exception ee) {}
}
if (out != null) {
try {
out.close();
} catch (Exception ee) {}
}
try {
socket.close();
} catch (Exception e) {}
}
socket = null;
}
}
There are ConnectionHandler threads which serving request and producing output on a socket. And my question is:
Does the reset() call still make any sense if there is a close() call immediately after it?
The original author just leaves one line comment // clear outputstream cache which makes me confused...
Appreciate your help!
No. reset() sends a tag over the wire that tells the peer to clear its handle table. As you're about to close the stream anyway, the reset operation has no meaning, and it's an extra network operation to go wrong. Just close it.
As for other problems:
Construct the ObjectOutputStream before the ObjectInputStream. Otherwise a deadlock can occur.
Use the try-with-resources syntax here. It will simplify the code a lot.

Socket connection closed unexpectedly

So I'm just testing out some client-server stuff (I was working on it in a larger project but it kept throwing errors, so I decided to make sure I was doing it right. Turns out I wasn't)
which involves ObjectOutput and Input streams. It works perfectly when I run client and server on localhost, but if I run server on my linux server and client on my computer, the connection has reset by the time I reach the line where the object is fetched. Here's the code:
Client:
public static void main(String[] args){
String[] stuff = {"test", "testing", "tester"};
Socket s = null;
ObjectOutputStream oos = null;
try {
s = new Socket("my.server.website", 60232);
oos = new ObjectOutputStream(s.getOutputStream());
oos.writeObject(stuff);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
s.close();
oos.close();
} catch (IOException e) {}
}
}
Server:
public static void main(String[] args){
ServerSocket ss = null;
Socket s = null;
ObjectInputStream ois = null;
try {
ss = new ServerSocket(60232);
s = ss.accept();
System.out.println("Socket Accepted");
ois = new ObjectInputStream(s.getInputStream());
Object object = ois.readObject();
System.out.println("Object received");
if (object instanceof String[]){
String[] components = (String[]) object;
for (String string : components){
System.out.println(string);
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
try {
ss.close();
s.close();
ois.close();
} catch (IOException e) {}
}
}
In the client, you are closing the underlying socket s before closing your output stream.
Try this:
try {
oos.close();
s.close();
} catch (IOException e) {}
The oos.close() should cause the object output stream to flush all it's data to the socket and then close the object stream. Then you can close the underlying socket.

Java Client/Server Socket Broken Pipe

I'm creating an update client via Sockets and I'm getting a Broken Pipe on the server side. The server accepts a client socket and responds to the same socket with either a message or a large byte array (~180MB). The error does not happen when testing locally (both client and server on the same machine) and it seems that it happens while sending the byte array. I'm not specifying a time out on the client socket and don't know why it is closing before reading the full response. Its my first time working with sockets and any help would be appreciated.
My Client Socket Code:
public static Response makeRequest(Request req) throws IOException {
Response response = null;
Socket echoSocket = null;
ObjectOutputStream out = null;
ObjectInputStream in = null;
echoSocket = new Socket(serverHost, 10008);
out = new ObjectOutputStream(echoSocket.getOutputStream());
in = new ObjectInputStream(
echoSocket.getInputStream());
BufferedReader stdIn = new BufferedReader(
new InputStreamReader(System.in));
out.writeObject(req);
try {
response = (Response)in.readObject();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.close();
in.close();
stdIn.close();
echoSocket.close();
return response;
}
Response is just a POJO holding the response (string/byte[] and other data)
My Server Code (copied an example of Sun/Oracle site and added my code to it)
public class Server extends Thread {
private Socket clientSocket;
public Server(Socket clientSocket) {
this.clientSocket = clientSocket;
start();
}
public void run()
{
{
System.out.println ("New Communication Thread Started");
try {
ObjectOutputStream out = new ObjectOutputStream(clientSocket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(clientSocket.getInputStream());
Request request = null;
try {
request = (Request)in.readObject();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
UpdateDAO dao = new UpdateDAO();
ClientDAO cdao = new ClientDAO();
Update update = null;
Client client = null;
Session s = HibernateUtil.currentSession();
Transaction t = s.beginTransaction();
if (request != null) {
client = cdao.getClient(request.getClientId());
LogItem log = new LogItem();
log.setClient(client);
log.setTimestamp(new Date());
log.setAction(request.getAction());
if (request.getResponse() != null) {
update = dao.getUpdate(request.getResponse().getUpdateId());
}
TaskContext ctx = new TaskContext(request, client, update, log);
System.out.println("Action: " + request.getAction().getDescription());
Task task = TaskFactory.getTask(request.getAction());
System.out.println(task.getClass().getName());
Response response = task.perform(ctx);
out.writeObject(response);
log.setClientTaskDescription(request.getMessage());
log.setUpdate(ctx.getUpdate());
dao.save(ctx.getLog());
if (ctx.getUpdate() != null) {
dao.update(ctx.getUpdate());
}
} else {
out.writeObject(new Response("what"));
}
t.commit();
out.close();
in.close();
clientSocket.close();
}
catch (IOException e)
{
e.printStackTrace();
System.exit(1);
}
}
}
public static void main(String[] args) throws IOException
{
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(10008);
System.out.println ("Connection Socket Created");
try {
while (true)
{
System.out.println ("Waiting for Connection");
new Server (serverSocket.accept());
}
}
catch (IOException e)
{
System.err.println("Accept failed.");
System.exit(1);
}
}
catch (IOException e)
{
System.err.println("Could not listen on port: 10008.");
System.exit(1);
}
finally
{
try {
serverSocket.close();
}
catch (IOException e)
{
System.err.println("Could not close port: 10008.");
System.exit(1);
}
}
}
}
If the client is, in fact, running out of memory:
java -Xmx512m -jar <the jar>
or
java -Xmx512m com.foo.blah.YourClass
would increase the maximum heap for the client/server. Keep in mind you may have to increase the heap for both sides of the pipe since both sides would be reading all ~180mb into memory at runtime.

Categories

Resources