I am trying to set the SO_KEEPALIVE time of socket.
I created a class SocketBuilder to build the socket instance with SocketImpl. Source code is below,
public class SocketBuilder {
private static SocketImpl si;
public static Socket createCVPSocket() throws Exception {
if (si == null) {
init();
}
return new CSocket(si);
}
private static void init() throws SocketException {
#SuppressWarnings("rawtypes")
Constructor cons = null;
try {
cons = Class.forName("java.net.SocksSocketImpl")
.getDeclaredConstructor();
} catch (NoSuchMethodException | SecurityException
| ClassNotFoundException e) {
throw new RuntimeException(
"Not able to access socket implementation.");
}
cons.setAccessible(true);
SocketImpl si = null;
try {
si = (SocketImpl) cons.newInstance();
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException("Not able to create instance of socket.");
}
if (si != null) {
si.setOption(SocketImpl.SO_KEEPALIVE, new Integer(60));
}
}
private static class CSocket extends Socket {
protected CSocket(SocketImpl si) throws SocketException, Exception {
super(si);
}
}
public static void main(String[] args) {
try {
Socket sock = SocketBuilder.createCVPSocket();
System.out.println(sock);
} catch (Exception e) {
e.printStackTrace();
}
}
}
I am getting java.net.SocketException: Socket Closed exception. If I remove the line si.setOption(SocketImpl.SO_KEEPALIVE, new Integer(60)); it works fine. But I want to set the SocketImpl.SO_KEEPALIVE. How can I set the SO_KEEPALIVE of socket?
There some errors in your code:
SocketImpl si = null; this declaration overlap your class field
setOption works only when a socket open/connected
You must close socket when you finish
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.*;
public class SocketBuilder {
private static SocketImpl si;
public static Socket createCVPSocket() throws Exception {
if (si == null) {
init();
}
return new CSocket(si);
}
private static void init() throws SocketException {
#SuppressWarnings("rawtypes")
Constructor cons = null;
try {
cons = Class.forName("java.net.SocksSocketImpl")
.getDeclaredConstructor();
} catch (NoSuchMethodException | SecurityException
| ClassNotFoundException e) {
throw new RuntimeException(
"Not able to access socket implementation.");
}
cons.setAccessible(true);
si = null;
try {
si = (SocketImpl) cons.newInstance();
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException("Not able to create instance of socket.");
}
}
private static class CSocket extends Socket {
protected CSocket(SocketImpl si) throws SocketException, Exception {
super(si);
super.bind(new InetSocketAddress("127.0.0.1", 8888));
si.setOption(SocketImpl.SO_KEEPALIVE, Boolean.TRUE);
}
}
public static void main(String[] args) {
try {
Socket sock = SocketBuilder.createCVPSocket();
System.out.println(sock);
} catch (Exception e) {
e.printStackTrace();
}
}
}
If you look at the source code of AbstractPlainSocketImpl#setOption method,
public void setOption(int opt, Object val) throws SocketException {
if (isClosedOrPending()) {
throw new SocketException("Socket Closed");
}
// Rest of the code removed for brevity
}
You can see there is a isClosedOrPending check before setting the options.
/*
* Return true if already closed or close is pending
*/
public boolean isClosedOrPending() {
/*
* Lock on fdLock to ensure that we wait if a
* close is in progress.
*/
synchronized (fdLock) {
if (closePending || (fd == null)) {
return true;
} else {
return false;
}
}
}
In your case, since you are just creating a socket, it will not have any fd associated with it. That is why you are getting this error.
Related
I have a class A that accepts TCP connection and send this new socket to Thread B where data from that socket is received and sent.
Class A{
Class b = new B();
public void run()
{
b.start();
while(true){
Socket socket = serverSocket.accept();
if(socket==null || socket.isClosed())continue;
b.setSocket(socket);
}
}
}
Class B extends Thread{
Socket socket;
public void setSocket(Socket p_socket) throws IOException
{
if(socket!=null && !socket.isClosed())
{
try{
socket.close();
socket = null;
Thread.sleep(5);
}
catch(Exception ex)
{}
}
socket = p_socket;
inputStream = socket.getInputStream(); // Here I am getting socket.closed() exception very much.
}
This worked fairly good in the past but now recently I am very very frequently getting the following error.
java.io.IOException: Socket Closed
at java.net.AbstractPlainSocketImpl.getInputStream(AbstractPlainSocketImpl.java:421)
at java.net.Socket$2.run(Socket.java:914)
at java.net.Socket$2.run(Socket.java:912)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.Socket.getInputStream(Socket.java:911)
I don't understand why this is happening now after years of working fine. Is this due to the network problem or Thread related something?
Updated:
Can this be the server related problem? Because the same application is running on other server but they are not having this problem.
The whole setup concept looks a bit broken. You should not "change" resources from the outside, while maybe there is still some work going on in that thread. A way better concept is to encapsulate the Socket into a new worker thread:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class WrapHandler {
static public class Server {
private final ServerSocket mSocket;
private final ArrayList<Handler> mRunningHandlers = new ArrayList<>();
public Server(final int pPort) throws IOException {
mSocket = new ServerSocket(pPort);
new Thread(() -> mainLoop()).start();
}
private void mainLoop() {
while (true) {
try {
#SuppressWarnings("resource") final Socket socket = mSocket.accept(); // do not close, do not handle with resource, socket will be closed by handler!
final Handler h = new Handler(socket, this);
handlerStarted(h);
} catch (final IOException e) {
e.printStackTrace(); // do something useful
}
}
}
synchronized void handlerStarted(final Handler pHandler) {
mRunningHandlers.add(pHandler);
}
synchronized void handlerEnded(final Handler pHandler) {
mRunningHandlers.remove(pHandler);
}
void handleException(final Handler pHandler, final Throwable pException) {
/* again do something useful */
}
}
static public class Handler {
private final Socket mSocket;
private final Server mServer;
public Handler(final Socket pSocket, final Server pServer) {
mSocket = pSocket;
mServer = pServer;
new Thread(() -> handleSocket()).start();
}
private void handleSocket() {
try {
handleData();
} catch (final IOException e) {
mServer.handleException(this, e);
} finally {
mServer.handlerEnded(this);
stop();
}
}
private void handleData() throws IOException {
mSocket.getInputStream().read();
/* data handling code here */
}
void stop() {
try {
mSocket.close();
} catch (final IOException e) { /* ignore or handle as you will */ }
}
}
}
Is there a way to get around during the serialization of the object full match / repetition of the way? For example:
on the client -
com.example.myProjectOne.model.MyClass
on the server side -
com.example.notMyProject.entity.MyClass
I get -
java.lang.ClassNotFoundException:
com.example.myProjectOne.model.MyClass
with the full coincidence of the names of all work packages
public class Server implements Runnable {
private SettingsConnection settingsConnection;
private OnReceiveObject onReceiveObject;
private Serializer serializer;
/**
* #param remoteServerAddress - address remote server
* #param inputPort - the port on which the is server
* #param outputPort - the port which used for send
* #param password - the password which should to be same on the client side and the server side
* #param handler - defines the name of the method, which should to be called, after received the data on server side
*/
public Server(String remoteServerAddress, int inputPort, int outputPort, String password, OnReceiveObject handler) {
settingsConnection = new SettingsConnection();
settingsConnection.setAddressRemoteServer(remoteServerAddress);
settingsConnection.setInputPort(inputPort);
settingsConnection.setOutputPort(outputPort);
this.onReceiveObject = handler;
serializer = new Serializer();
new Thread(this).start();
}
public void sendData(Serializable object, String callBackFunction) {
Container container = new Container();
try {
container.setData(serializer.serialize(object), container.getInitVector()));
container.setHandler(callBackFunction);
InetAddress ipAddress = InetAddress.getByName(settingsConnection.getAddressRemoteServer());
try (Socket socketConnectionToSever = new Socket(ipAddress, settingsConnection.getOutputPort())) {
OutputStream outputStream = socketConnectionToSever.getOutputStream();
if (outputStream != null) {
outputStream.write(serializer.serialize(container));
outputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
final ExecutorService asyncTakesCode = Executors.newCachedThreadPool();
Runnable threadTaskServer = new Runnable() {
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(settingsConnection.getInputPort());
while (true) {
Socket connectionSocketClient = serverSocket.accept();
asyncTakesCode.submit(new ThreadTaskClient(connectionSocketClient));
}
} catch (IOException e) {
System.err.println("Unable to process client request");
e.printStackTrace();
}
}
};
Thread threadServer = new Thread(threadTaskServer);
threadServer.start();
}
private class ThreadTaskClient implements Runnable {
private final Socket connectionSocketClient;
private ThreadTaskClient(Socket connectionSocketClient) {
this.connectionSocketClient = connectionSocketClient;
}
#Override
public void run() {
InputStream inputStream = null;
try {
inputStream = connectionSocketClient.getInputStream();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
Object o = serializer.deserialize(IOUtils.readFully(inputStream, -1, false));
if (o instanceof Container) {
Container container = (Container) o;
Serializable remoteObject = (Serializable) serializer.deserialize(container.getData()));
String callBackFunction = container.getHandler();
onReceiveObject.processRemoteObject(remoteObject, callBackFunction);
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
connectionSocketClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
If you're using java's serialization, the classes must match both ends.
Include your class in the server side's classpath.
If you can't do that, you could make it work by effectively creating an alias of your class name for the other class:
package com.example.myProjectOne.model;
public class MyClass extends com.example.notMyProject.entity.MyClass {
}
There are a few caveats of course, for example the would only work if the two classes share the same non-transient instance field names and types.
Yes, you can. You have to extend the default ObjectInputStream and override the resolveClass method (maybe others, not sure).
So, for example:
ObjectInputStream ois = new ObjectInputStream( lis ) {
protected Class<?> resolveClass(ObjectStreamClass osc) throws IOException, ClassNotFoundException {
if (osc.getName().contains("some.package.element")) {
try {
Field nameField = osc.getClass().getField("name");
nameField.setAccessible(true);
nameField.set(osc, osc.getName().replace("some.package.element", "another.package.element"));
nameField.setAccessible(false); // hack because "name" is private
} catch (NoSuchFieldException | IllegalAccessException e) {
// ...
}
}
return super.resolveClass(osc);
}
}
This question already has answers here:
Java socket API: How to tell if a connection has been closed?
(9 answers)
Closed 7 years ago.
i am trying to make a chat program. The problem i am having is that my loop in the EchoThread always thinks that the connection is true. I have tried to use if(s.isConnected() == false) but that didn't work also i tried to do if(s.isClosed() == true) if you can help thank you in advance. Here is my code
import java.io.*;
import java.net.*;
import java.util.ArrayList;
public class server {
public ObjectInputStream input;
public ServerSocket server;
public Socket s;
public ObjectOutputStream output;
public ArrayList<ObjectOutputStream> outputs = new ArrayList<ObjectOutputStream>();
public ArrayList<Socket> users = new ArrayList<Socket>();
public class Accept implements Runnable {
public void run() {
try {
server = new ServerSocket(55555, 100);
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
try {
s = server.accept();
new EchoThread(s).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class EchoThread extends Thread {
private Socket s1;
public EchoThread(Socket s) throws IOException {
this.s1 = s;
}
public void run() {
users.add(s1);
try {
outputs.add(new ObjectOutputStream(s1.getOutputStream()));
newUser();
} catch (IOException e) {
System.out.println("Error 2");
}
while(s1.isConnected() == true) {
// loops until socket looses connection
}
System.out.println("Disconnected");
}
}
public class check implements Runnable {
public void run() {
}
}
public void newUser() {
try {
for(ObjectOutputStream o: outputs) {
o.writeObject(s.getInetAddress() + " Connected");
}
} catch (IOException e1) {
System.out.println("Error 21");
}
}
server() throws IOException {
Thread t = new Thread(new Accept());
t.start();
Thread ch = new Thread(new check());
ch.start();
}
public static void main(String[] args) throws IOException {
new server();
}
}
you have to read this, you have to check with the read()method to check if it returns -1.
https://stackoverflow.com/a/10241044/964152
while(s1.isConnected() == true) {
This is not a valid loop. isConnected() is true because you accepted the socket, and it doesn't magically become false afterwards. When the client disconnects, you will get the appropriate end of stream indication from whichever read method you're calling.
try-with-resources is nice and all that, but it seems to me that it is still not sufficient for effective resource management when creating classes that wrap multiple AutoCloseable objects. For example, consider
import java.io.*;
class AutocloseableWrapper implements AutoCloseable {
private FileReader r1;
private FileReader r2;
public AutocloseableWrapper(String path1, String path2) throws IOException {
r1 = new FileReader(path1);
r2 = new FileReader(path2);
}
#Override
public void close() throws IOException {
r1.close();
r2.close();
}
public static void main(String[] args) throws IOException {
try (AutocloseableWrapper w = new AutocloseableWrapper("good-path", "bad-path")) {
System.out.format("doing something\n");
throw new IOException("doing something in main");
}
}
}
There are at least two issues with this wrapper:
If "bad-path" is invalid and causes the assignment to r2 to throw, then r1 is not closed.
If wrapper construction succeeds but then r1.close throws, then r2 is not closed.
All those issues can be addressed, but then writing the wrapper becomes quite non-trivial and error-prone, even if wrapping only two resources:
import java.io.*;
class AutocloseableWrapper implements AutoCloseable {
private FileReader r1;
private FileReader r2;
public AutocloseableWrapper(String path1, String path2) throws IOException {
r1 = new FileReader(path1);
try {
r2 = new FileReader(path2);
}
catch (IOException e) {
try {
r1.close();
}
catch (IOException e2) {
e.addSuppressed(e2);
}
throw e;
}
}
#Override
public void close() throws IOException {
IOException e = null;
try {
r1.close();
}
catch (IOException e1) {
e = e1;
}
try {
r2.close();
}
catch (IOException e2) {
if (e == null)
throw e2;
else {
e.addSuppressed(e2);
throw e;
}
}
}
public static void main(String[] args) throws IOException {
try (AutocloseableWrapper w = new AutocloseableWrapper("good-path", "bad-path")) {
System.out.format("doing something\n");
throw new IOException("doing something in main");
}
}
}
Is there some helper class or any other way to make writing wrappers easier?
You should enable the syntactic code unwrapped by the compiler....You can find the Oracle article over here :-
http://www.oracle.com/technetwork/articles/java/trywithresources-401775.html
Coming to the question,if you have a wrapper you can do something like this
#Override
public void close() throws IOException {
Throwable t = null;
try {
r1.close();
} catch (Throwable t1) {
t = t1;
throw t1;
} finally {
if (t != null) {
try {
r2.close();
} catch (Throwable t2) {
t.addSuppressed(t2);
}
} else {
r2.close();
}
}
}
Note:This will work because of precise rethrow feature in Java 7
You could use a generic resource wrapper such as:
public class CloseableChain implements AutoCloseable {
private AutoCloseable r1;
private CloseableChain r2;
public void attach(AutoCloseable r) {
if (r1 == null) {
r1 = r;
} else {
if (r2 == null) {
r2 = new CloseableChain();
}
r2.attach(r);
}
}
public void close() throws Exception {
if (r1 == null) {
return;
}
Throwable t = null;
try {
r1.close();
} catch (Throwable t1) {
t = t1;
throw t1;
} finally {
if (r2 != null) {
if (t != null) {
try {
r2.close();
} catch (Throwable t2) {
t.addSuppressed(t2);
}
} else {
r2.close();
}
}}}}
Then you could refactor your code to:
import java.io.*;
class AutocloseableWrapper implements AutoCloseable {
private CloseableChain chain;
private FileReader r1;
private FileReader r2;
private FileReader r3;
public AutocloseableWrapper(String path1, String path2) throws IOException {
chain = new CloseableChain();
r1 = new FileReader(path1);
chain.attach(r1);
r2 = new FileReader(path2);
chain.attach(r2);
// and even more...
r3 = new FileReader("whatever");
chain.attach(r3);
}
#Override
public void close() throws IOException {
chain.close();
}
public static void main(String[] args) throws IOException {
try (AutocloseableWrapper w = new AutocloseableWrapper("good", "bad")) {
System.out.format("doing something\n");
throw new IOException("doing something in main");
}
}
}
class SomeUI
{
SocketMessageSender messageSender;
// ensure that its initialized ...
private void bSendMessageActionPerformed(java.awt.event.ActionEvent evt) {
try {
// TODO add your handling code here:
messageSender.sendMessage(jMessage.getText());
jMessage.setText("");
} catch (IOException ex) {
Logger.getLogger(TeKServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
ERROR: Exception in thread "AWT-EventQueue-0" java.lang.RuntimeException: Uncompilable source code - Erroneous sym type: bSendMessageActionPerformed
Why do you keep opening the socket and closing it on every button click. Create a class that allow you to keep the socket open for as long as your application run. The socket connection can be done when the application starts.You can try out the following class
public class SocketMessageSender
{
private String host;
private int port;
private DataOutputStream dos;
public SocketMessageSender(String host, int port)
{
this.host = host;
this.port = port;
}
// call when application starts
public void initConnection() throws IOException
{
InetAddress address = InetAddress.getByName(host);
Socket connection = new Socket(address, port);
dos = new DataOutputStream(connection.getOutputStream());
}
//call from button click
public void sendMessage(String message) throws IOException
{
if(dos != null)
{
dos.writeUTF(message);
dos.flush();
}
}
// call when application exits
public void closeConnection() throws IOException
{
if(dos!= null)
{
dos.close();
}
}
}
Hope it helps ...
Assume you have a class like
class SomeUI
{
SocketMessageSender messageSender;
// ensure that its initialized ...
private void bSendMessageActionPerformed(java.awt.event.ActionEvent evt) {
messageSender.sendMessage(jMessage.getText());
jMessage.setText("");
}
}
I think that the class signature should be something like this ....
public class MyPanel extends JPanel implements ActionListener
{
private SocketMessageSender messageSender;
private Message jMessage = new Message();// This is just a temp class, replace this with your class
public MyPanel()
{
messageSender = new SocketMessageSender("some host", 8080);
try
{
messageSender.initConnection();
}
catch(IOException e)
{
Logger.getLogger(MyPanel.class.getName()).log(Level.SEVERE, null, e);
}
}
#Override
public void actionPerformed(ActionEvent e)
{
try {
// TODO add your handling code here:
messageSender.sendMessage(jMessage.getText());
jMessage.setText("");
} catch (IOException ex) {
Logger.getLogger(MyPanel.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Consider using ObjectOutputStream/ObjectInputStream and write object through sockets.
There are a lot of examples at java2s.com
Please mind that if you are writing same object multiple times, you will need to reset() stream before writing, and flush after it.