How wait a ServerSocket connection on client Socket - java

I am wondering about, how I can wait a ServerSocket connection on Socket client side.
When I execute the server (send) first, it waits the client connection with the method ServerSocket.accept. The problem is that the client (receive) cannot be executed without the server has been executed first. I would like add a condition to allow the client to wait the connection from the server. Is it possible?
SEND (server)
ServerSocket servsock = new ServerSocket(1234);
Socket sock = servsock.accept();
RECEIVE (client)
Socket sock = new Socket(from, 1234);
ERROR (client)
java.net.ConnectException: Connection refused
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:432)
at java.net.Socket.connect(Socket.java:529)
at java.net.Socket.connect(Socket.java:478)
at java.net.Socket.<init>(Socket.java:375)
at java.net.Socket.<init>(Socket.java:189)
Thank you.

There is no built-in way to do that. You'll have to catch the exception on the client side, and implement a retry mechanism yourself.
Pseudo-code:
Socket sock = null;
while (retryCounter < threshold) {
try {
retryCounter++;
sock = new Socket(form, 1234);
} catch (...) {
// handle exceptions
// possibly add a sleep period
}
}
if (sock == null) {
// you failed to connect
} else {
// you're connected
}
Be careful if you have a GUI: you might need to implement some of that in a separate thread or use timers to avoid freezing your UI.

Thank to Mat, it works.
Socket sock = null;
while (true) {
try {
sock = new Socket(from, 1234);
if (sock != null) { break; }
}
catch (IOException e) { Thread.sleep(1000); }
}
// rest of the code

Related

Oreo: LocalOnlyHotspot is created, but socket exception happens

I am creating some testing app, and I need to connect several devices via Wi-Fi direct. On Android 8 the only way to do it is to create LocalOnlyHotspot. I have done it successfully, devices are connecting. However I need to transfer some strings between devices. For those reason I have made in separate threads
-> on server side
try{
int port = 9802;
ServerSocket serverSocket = new ServerSocket(port);
running = true;
while (running){
Socket socket = serverSocket.accept();
}
} catch (IOException e) { e.printStackTrace(); }
-> on client side
Socket socket = null;
try{
socket = new Socket(address, port);
} catch (IOException e) { e.printStackTrace(); }
I am always getting an exception on client's side
failed to connect to /192.168.43.1 (port 9802) from /:: (port 33044): connect failed: ECONNABORTED (Software caused connection abort)
As I have googled the reason is that the network has no internet connection.
How can I solve this problem? Is any other way to pass strings between 2 devices on Android 8 using Wi-Fi direct?
Thanks in advance.

Android,Java,socket, determine remote host disconnect

I'm trying to code a TCP client in android java. Most works fine. But i have one issue. If the socket is connected and the remeote host shuts down or the network goes down or something else, the socket.getinputstream keeps blocking.
I don't know if the socket is still connected. I code in objective-c too and in objective-c i get an event that the socket forcefully shuts down and i can try to reconnect. So on objective c the socket tracks the state.
In java the socket and the inputstream is still connected or blocked even the socket is down. How can i check if the socket is still connected?
#Override
protected Void doInBackground(String... params) {
try {
String host = params[0];
int port = Integer.parseInt(params[1]);
SocketAddress sockaddr = new InetSocketAddress(host, port);
Socket socket = new Socket();
socket.connect(sockaddr,5000);
socket.setSoTimeout(7000);
out = new PrintWriter(socket.getOutputStream(), true);
mBufferIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (mRun) {
try {
-----> mServerMessage = mBufferIn.readLine();
}catch (Exception e){
Log.d("my","hier3" + e.getMessage());
}
if (mServerMessage.trim() != null) {
sender.messageReceived(s2);
}else{
}
}
}
} catch (UnknownHostException e
) {
The question of how to detect if the remote peer/socket has closed the connection has been answered here as well as here.
Basically, the answers suggest that you attempt to read from the socket, and then observe what happens (read() returns -1, or readLine() returns null or your read methods raise EOFException.

Socket verification from ServerSocket Java

i'm trying create "multi-client -- single server" connection.
My client(s) opens connection and in the server side I've create
Client clt = new Client("127.0.0.1", 9000);
clt.openConn();
...
public Client(String serverAddress, int serverPort) {
this.serverAddress = serverAddress;
this.serverPort = serverPort;
}
try {
this.clientSocket = new Socket(this.serverAddress, this.serverPort);
this.clientSocket.setKeepAlive(true);
this.clientSocket.setSoTimeout(0);
oos = new DataOutputStream(this.clientSocket.getOutputStream());
ois = new DataInputStream(this.clientSocket.getInputStream());...}
...
on the server side i've created ListArray of ServerSocket's each onf them I wrapped on the Thread.
ServerSocket serverSocket = null ;
Socket clientSocket;
boolean listening = true;
ArrayList threadList = new ArrayList();
Iterator itSrvThr;
try {
serverSocket = new ServerSocket(port);
} catch (IOException e) {
System.err.println("Could not listen on port: " + port + ".");
System.exit(-1);
}
while (listening) {
clientSocket = serverSocket.accept();
ServerThread srvThread = new ServerThread(clientSocket);
srvThread.start();
`...`
}
where
ServerThread extends Thread
{...
public void run() {
this.ois = new DataInputStream(socket.getInputStream());
this.oos = new DataOutputStream(socket.getOutputStream());
}
}
my program send and receive objects(i've called them "Datagramm") which are some kind of wrappers for file and strings (let us say it is some language for client-server)
And now about problem which I have. I must to make verification every time when need to test for "alive" socket from server side...
i'm trying to make this verification when appears new element in the ArrayList in that moment but it brings me problem with "Datagramm's" sending
itSrvThr = threadList.iterator();
while (itSrvThr.hasNext()) {
ServerThread st = (ServerThread) itSrvThr.next();
boolean stoppedSocket = st.getStopped();
if (stoppedSocket) {
st.stop();
itSrvThr.remove();
}else {??? resolution???}
stoppedSocket - it's a value which significate programly turned off socket from client site.
Honestly, i'm working with sockets and threads only a couple weeks, that is why every help and critics will be acceptable.
...
Thank for answer but I have problems with codding of heartbeats. First of them where exactly the place of heartbeat must be placed on the server side.
I suggest you send a heartbeat message from the client and/or the server whenever you haven't sent a message for a while (seconds) The other end can timeout when you haven't recieved anything for some multiple of this time.
If you have a protocol like {message length} {message} I use a message-length=0 as a heartbeat.

Java TCP SO_RESUEADDR, cannot connect

I don't know how to clearly describe my question in title, as for me it is a little complicated. What i am doing is try to implement a TCP peer to peer demo, in which a local port must be both for listening and initiating a socket.
I will give a detailed description.
I will give a java implementation which will listen and initiate connection on a single local port. Code will explain my idea.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Just for testing socket SO_RESUEADDR. If set SO_RESUEADDR to true, we can use
* a single local port to listen for incoming TCP connections, and to initiate
* multiple outgoing TCP connections concurrently. By this way we can implement
* TCP hole punching(establish P2P connection traversal through NAT over TCP).
*/
public class TcpPeer {
// TCP port is a different source from UDP port, it means you can listen on
// same port for both TCP and UDP at the same time.
private int localport = 7890;
private ServerSocket peerSock;
private Socket serverSocket;
public TcpPeer(final String serverHost, final int serverPort, final int localPort)
throws Exception {
this.localport = localPort;
Thread server = new Thread(new Runnable() {
#Override
public void run() {
try {
peerSock = new ServerSocket();
peerSock.setReuseAddress(true);
peerSock.bind(new InetSocketAddress("localhost", localport));
System.out.println("[Server]The server is listening on " + localport + ".");
while (true) {
try {
serverSocket = peerSock.accept();
// just means finishing handshaking, and connection
// established.
System.out.println("[Server]New connection accepted"
+ serverSocket.getInetAddress() + ":" + serverSocket.getPort());
BufferedReader br = getReader(serverSocket);
PrintWriter pw = getWriter(serverSocket);
String req = br.readLine();
System.out.println("[Server][REQ]" + req);
pw.println(req);
pw.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (serverSocket != null)
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
// server.setDaemon(true);
server.start();
Thread.currentThread();
// sleep several seconds before launch of client
Thread.sleep(5 * 1000);
final int retry = 5;
Thread client = new Thread(new Runnable() {
#Override
public void run() {
Socket socket = new Socket();
try {
socket.setReuseAddress(true);
System.out.println("[Client]socket.isBound():" + socket.isBound());
socket.bind(new InetSocketAddress("localhost", localport));
for (int i = 1; i < retry; i++) {
try {
socket.connect(new InetSocketAddress(serverHost, serverPort));
System.out.println("[Client]connect to " + serverHost + ":"
+ serverPort + " successfully.");
break;
} catch (Exception e) {
e.printStackTrace();
System.out.println("[Client]fail to connect " + serverHost + ":"
+ serverPort + ", try again.");
Thread.currentThread().sleep(i * 2 * 1000);
if (i == retry - 1) return;
}
}
PrintWriter pw = getWriter(socket);
String msg = "hello world!";
pw.println(msg);
/**
* Got response from the server socket.
*/
BufferedReader br = getReader(socket);
String resp = br.readLine();
System.out.println("[Client][RESP-1]" + resp);
pw.close();
br.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
client.start();
}
private PrintWriter getWriter(Socket socket) throws IOException {
OutputStream socketOut = socket.getOutputStream();
return new PrintWriter(socketOut, true);
}
private BufferedReader getReader(Socket socket) throws IOException {
InputStream socketIn = socket.getInputStream();
return new BufferedReader(new InputStreamReader(socketIn));
}
public static void main(String[] args) throws Exception {
if (args.length != 3) {
System.out.println("[Usage] java " + TcpPeer.class.getCanonicalName()
+ " [serverHost] [serverPort] [localPort]");
System.exit(0);
}
new TcpPeer(args[0], Integer.parseInt(args[1]), Integer.parseInt(args[2]));
}
}
Now we launch 2 jvm processes:
ps#1> java TcpPeer localhost 2000 4000
ps#2> java TcpPeer localhost 4000 2000
Finally when 2 processes got stable, they will give below outputs:
ps#1>
[Server]The server is listening on 2000.
[Client]socket.isBound():false
[Client]connect to localhost:4000 successfully.
[Client][RESP-1]hello world!
ps#2>
[Server]The server is listening on 4000.
[Server]New connection accepted/127.0.0.1:2000
[Server][REQ]hello world!
[Client]socket.isBound():false
java.net.BindException: Address already in use: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
at java.net.Socket.connect(Socket.java:525)
at java.net.Socket.connect(Socket.java:475)
at org.clinic4j.net.TcpPeer$2.run(TcpPeer.java:92)
at java.lang.Thread.run(Thread.java:619)
[Client]fail to connect localhost:2000, try again.
java.net.SocketException: Socket operation on nonsocket: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
at java.net.Socket.connect(Socket.java:525)
at java.net.Socket.connect(Socket.java:475)
at org.clinic4j.net.TcpPeer$2.run(TcpPeer.java:92)
at java.lang.Thread.run(Thread.java:619)
[Client]fail to connect localhost:2000, try again.
java.net.SocketException: Socket operation on nonsocket: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
at java.net.Socket.connect(Socket.java:525)
at java.net.Socket.connect(Socket.java:475)
at org.clinic4j.net.TcpPeer$2.run(TcpPeer.java:92)
at java.lang.Thread.run(Thread.java:619)
[Client]fail to connect localhost:2000, try again.
java.net.SocketException: Socket operation on nonsocket: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
at java.net.Socket.connect(Socket.java:525)
at java.net.Socket.connect(Socket.java:475)
at org.clinic4j.net.TcpPeer$2.run(TcpPeer.java:92)
at java.lang.Thread.run(Thread.java:619)
[Client]fail to connect localhost:2000, try again.
From the output, we can figure out that interaction flow as below:
ps#1 listen on 2000.
ps#2 listen on 4000.
ps#1 connect to ps#2, from localhost:2000 -> localhost:4000.
ps#2 close the connection which established at step#3.
ps#2 try to connect to ps#1 at 2000, failed!
Why ps#2 cannot connect to ps#1 at step#4? I also monitor the net status of OS.
Below is net status right after step#3.
And also the net status right after step#4.
192.168.2.107 is localhost
Could you please give me a comment on my case? thanks!
I have printed out the original exception message when fail to reconnect, but i don't have much idea about those exception.
You shouldn't bind the client socket, and also not set the SO_REUSEADDR on client socket.
If you do not bind a client socket, the system will automatically assign a port number for you.
Also, SO_REUSEADDR doesn't mean the address (ip/port numbers) can be reused while the socket is still open. It's so that when a socket has been closed and is in the TIME_WAIT state, you can bind to that again.
Your client thread exits just after the first exchange of messages, it lacks while(true) part.
If you get through your connection retries without a successful connection you need to quit, not fall through into the I/O code. This is why you are getting the actual exception.
You also need to print out why the connections are failing. At the moment this is the most important information, and you are suppressing it. Print the exception message. This is a general principle: don't make up your own message, use the one you're given. It is almost certainly more specific.
Instead of new InetAddress("localhost") use null when binding the ServerSocket.
I'm not convinced that you can retry a connect on a socket. If it fails, try creating a new Socket.

Close listening ServerSocket

In my Server application I'm trying to handle the Server which is using ServerSocket like,
Start the server and wait for connection.
Stop the server which is connected with a client.
Stop the server which is waiting for a client.
I can able to start the server and make it to wait for client inside a thread using
socket = serverSocket.accept();
What I want to do is I want manually close the socket which is waiting for connection, I have tried using,
if (thread != null) {
thread.stop();
thread = null;
}
if (socket != null) {
try {
socket.close();
socket = null;
}
catch (IOException e) {
e.printStackTrace();
}
}
After executing the above code even though the socket becomes null, when I try to connect from client to server, the connection gets established, so my question is how to interrupt the serversocket which listening for connection over here,
socket = serverSocket.accept();
I think a common way of handling this is make the accept() call time out in a loop.
So something like:
ServerSocket server = new ServerSocket();
server.setSoTimeout(1000); // 1 second, could change to whatever you like
while (running) { // running would be a member variable
try {
server.accept(); // handle the connection here
}
catch (SocketTimeoutException e) {
// You don't really need to handle this
}
}
Then, when you wanted to shut down your server, just have your code set 'running' to false and it will shut down.
I hope this makes sense!
Just close the ServerSocket, and catch the resulting SocketClosedException.
And get rid of the thread.stop(). For why, see the Javadoc.

Categories