I'm using Socket class for my TCP connection. But my current problem is to determine exactly disconnect reason.
In both cases (if there's connection timeout or server closed connection) I receive SocketException with "Broken pipe" message. So how I can exactly determine disconnect reason?
Thanks!
I think you should get a different Exception thrown. If you are talking about a connection then you should get a SocketException from a host which sends a reset (I think that's the RST packet) and a SocketTimeoutException if your connection times out.
If you are talking about IO then again, if the server drops the connection you will get a SocketException while if the IO times out (maybe just the read) you will get a SocketTimeoutException.
Here's the test program I used. Of course I'm bleeding sockets like crazy.
try {
new Socket().connect(new InetSocketAddress(someIpThatHangs, 8000), 1000);
fail("Should have thrown");
} catch (SocketTimeoutException e) {
// we expected it to timeout
}
try {
new Socket().connect(new InetSocketAddress(someIpThatResets, 1000));
fail("Should have thrown");
} catch (SocketException e) {
// we expected it to throw an exception immediately on reset
}
// start our server
final ServerSocket serverSocket = new ServerSocket();
int serverPort = 8000;
InetSocketAddress address = new InetSocketAddress("127.0.0.1", serverPort);
serverSocket.bind(address);
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Socket clientSocket = serverSocket.accept();
System.err.println("Got a connection");
Thread.sleep(1000);
clientSocket.close();
} catch (InterruptedException e) {
return;
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
});
thread.start();
// wait for the server to start
Thread.sleep(100);
Socket clientSocket = new Socket();
clientSocket.connect(address);
try {
// read until the server closes the connection
clientSocket.getInputStream().read();
} catch (SocketException e) {
// expected socket exception
}
clientSocket = new Socket();
clientSocket.connect(address);
clientSocket.setSoTimeout(100);
try {
// read until the socket timeout expires
clientSocket.getInputStream().read();
} catch (SocketTimeoutException e) {
// expected read timeout exception
}
serverSocket.close();
thread.interrupt();
Related
A client communicate with authserver to recieve a nickname, and the auhserver send the nickname to clients and another server, in order to client communicate with the other server.
My problem is how to make the other server connect with the client and authserver without making new communication thread for each one?
public class Aatombolaserver extends Thread {
/***in order to differentiate between client socket**/
protected Socket clientSocket;
String serverHostname = new String ("127.0.0.1");
Socket authSocket = null;
/**** constructor**/
private Aatombolaserver (Socket clientSoc)
{clientSocket = clientSoc;
authSocket = clientSoc;
//store the socket of the coming client
start();//execute the run method
}
public static void main(String[] args) throws IOException
{
/**** Create a server socket and wait for a connection**/
ServerSocket serverSocket = null;
// ServerSocket serverSocket1 = null;
try {
serverSocket = new ServerSocket(9091);
// serverSocket1 = new ServerSocket(9092);
System.out.println ("Connection Socket Created");
try { System.out.println ("Waiting for a client to connect");
while (true){//wait for clients
//accept the client request and proceed with the thread creation
new Aatombolaserver(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);
}//end try
/************Close Socket*******************/
finally {
try { serverSocket.close(); }
catch (IOException e){
System.err.println("Could not close port: 10008.");
System.exit(1);
}
}//end finally
}
I have a client-server application. Right now, I'm trying to test sending messages from the client to the server and then read them from the server. I'm using ObjectInputStream and ObjectOutputStream to transfer message objects between the client and server.
However, when I try to write an object from the client, it results in a SocketException.
Server code:
while (true) {
try {
log.trace("Waiting for connection.");
Socket clientSocket = socket.accept();
log.trace("Socket connected");
/* create thread */
new Thread(new RequestRunner(clientSocket, serverID)).start();
} catch (SocketTimeoutException e) {
log.trace("Socket timed out.");
socket.close();
break;
} catch (IOException e) {
log.error("Cannot accept connection...");
break;
}
}
Server Thread:
public class RequestRunner implements Runnable {
....
public RequestRunner(Socket socket, UUID serverID) {
client = socket;
this.serverID = serverID;
}
/**
* Start the thread for the request
*/
public void run() {
log.trace("Thread started for socket");
try {
out = new ObjectOutputStream(client.getOutputStream());
in = new ObjectInputStream(client.getInputStream());
} catch (IOException e) {
log.error("Cannot intialize streams...");
return;
}
while(client.isConnected()) {
/* initialize streams */
try {
/* read message */
Object obj = in.readObject(); // does not block
MessageFrame msg = (MessageFrame) obj;
processRequest(msg);
} catch (IOException e) {
; // triggers everytime
//log.error("IO error occured while trying to get input/output stream from socket");
} catch (ClassNotFoundException e) {
log.error("Cannot read MessageFrame");
}
}
}
}
Client code:
public void init(int port) throws IOException {
log.trace("intializing to port " + port);
clientID = UUID.randomUUID();
socket = new Socket("0.0.0.0",port);
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
}
public void sendEcho() throws Exception {
while(socket.isConnected()) {
try {
log.trace("Sending echo..");
msg = new EchoMessage(clientID);
curMsgID = msg.getMsgID();
out.writeObject(msg); // throws SocketException, socket closed
out.flush();
break;
} catch (SocketException e) {
log.error ("Cannot send echo.. socket closed.");
break;
} catch (IOException e) {
continue;
}
}
}
The statement out.writeObject(msg) causes a ServerSocket exception with Socket closed as the reason. And the server does not register receiving an object from in.readObject().
netstat shows the connection as established, the error occurs when I try to write the object.
What am I doing wrong ?
You should only have one InputStream and one OutputStream.
out = new ObjectOutputStream(client.getOutputStream());
in = new ObjectInputStream(client.getInputStream());
Should be:
out = client.getOutputStream();
in = client.getInputStream()
And you should change it in the client code when getting the streams from the sockets as well.
My code is as follows. When request comes, server creates two threads (producer-consumer pattern):
...
while(true) {
Socket clientSocket = server.accept();
System.out.println("Got connection!");
Thread consumerThread = new Thread(new ConsumerThread(sharedQueue, clientSocket));
Thread producerThread = new Thread(new ProducerThread(sharedQueue, clientSocket));
consumerThread.start();
producerThread.start();
}
...
Consumer thread reads what client sent and producer thread responds back. Consumer:
#Override
public void run() {
try {
while (true) {
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// read, do actions
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Producer:
#Override
public void run() {
try {
out = new PrintStream(clientSocket.getOutputStream(), true);
// some actions
out.println("something");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
out.close();
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
But in server I get following error:
java.net.SocketException: Socket closed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:150)
at java.net.SocketInputStream.read(SocketInputStream.java:121)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at ee.ut.ds.server.ConsumerThread.run(ConsumerThread.java:30)
at java.lang.Thread.run(Thread.java:745)
What might cause this? I even see that client accepts message correctly. Also, in producer thread I close a socket. I do not understand.
You closed the socket and continued to use it.
Don't close the socket, or its output stream, until you have read end of stream from the BufferedReader.
Construct the BufferedReader outside the loop.
You probably don't need two threads per socket.
You are starting both the threads in parallel. You can't predict the behvaiour of threads. You are using the same socket for both the threads and if producer thread starts you are closing socket in finally section.
you should not close the connection and make sure the race condition should not occur.
The problem is because you are closing the socket from your produce after writing something to it.
If you want the socket to be open, just close the output stream in the finally block in Producer.
You can close the socket from Server/Producer/Consumer once you are sure that there is no more network I/O to happen over the socket.
https://docs.oracle.com/javase/7/docs/api/java/net/Socket.html#close()
I am using a server socket in linux and I need to close it and reopen before the time_wait TCP status expires. I set the reuse address option of the server socket before the binding but it still throws a BindException.
I also tried this http://meteatamel.wordpress.com/2010/12/01/socket-reuseaddress-property-and-linux/ but it still doesn't work.
To open a server socket i use:
ServerSocket ss = new ServerSocket();
ss.setReuseAddress(true);
ss.bind(new InetSocketAddress(12345));
and to close:
ss.close();
The "Address already in use" BindException is throwed at the bind call.
This code generates the exception:
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
#Override
public void run() {
try {
final ServerSocket ss = new ServerSocket();
ss.setReuseAddress(true);
ss.bind(new InetSocketAddress(12345));
Socket s = ss.accept();
System.out.println((char) s.getInputStream().read());
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
Thread.sleep(500);
Socket s = new Socket("localhost", 12345);
s.getOutputStream().write('c');
}
You set reuse before binding not after you get an exception.
ServerSocket ss = new ServerSocket(); // don't bind just yet
ss.setReuseAddress(true);
ss.bind(new InetSocketAddress(12345)); // can bind with reuse= true
This runs without error on Windows 7 and RHEL 5.x
for (int i = 0; i < 1000; i++) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
final ServerSocket ss = new ServerSocket();
ss.setReuseAddress(true);
ss.bind(new InetSocketAddress(12345));
Socket s = ss.accept();
System.out.println((char) s.getInputStream().read());
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
Thread.sleep(50);
Socket s = new Socket("localhost", 12345);
s.getOutputStream().write('c');
t.join();
}
You have to do that: it means extract the code so that it does not recur constantly
public class....
private ServerSocket socServer;
onCreate
...
try {
socServer = new ServerSocket();
socServer.setReuseAddress(true);
socServer.bind(new InetSocketAddress(SERVER_PORT));
} catch (IOException e) {
e.printStackTrace();
}
// New thread to listen to incoming connections
new Thread(new Runnable() {
#Override
public void run() {
try
{
// Create server side client socket reference
Socket socClient = null;
// Infinite loop will listen for client requests to connect
while (true) {
// Accept the client connection and hand over communication
// to server side client socket
socClient = socServer.accept();
// For each client new instance of AsyncTask will be created
ServerAsyncTask serverAsyncTask = new ServerAsyncTask();
// Start the AsyncTask execution
// Accepted client socket object will pass as the parameter
serverAsyncTask.execute(new Socket[] {socClient});
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
I tried to build a socket channel between two emulators in android. I wrote the following code:
public SocketChannel connect2node(String ip, int port) {
SocketChannel client = null;
try {
client = SocketChannel.open(new InetSocketAddress(ip, port));
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
if (!client.isConnected()) {
Log.i("server connection", "error");
return null;
}
} catch (IOException e) {
String s = e.getMessage();
e.printStackTrace();
}
return client;
}
Note I have NOT started another emulator in (ip, port), means the connection will always fail. When I start debugging the above code, I found when it came to
if (!client.isConnected()) {
It then jumps to the catch block:
e.printStackTrace();
all other lines in catch block is not executed, and the client is not null when return. So how can I tell whether the connection is successfully established or not?
The isConnected() test is pointless. If the open() fails to connect it will throw an exception.