opening a Java socket vs. Telnet? - java

If I execute the following code (NOTE: not the real IP address being used)
Socket s = new Socket("120.200.100.111", 80);
s.setSoTimeout(10 * 1000);
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
in.readLine();
After 10 seconds, I get 'SocketTimeoutException: Read timed out'
But if I telnet, I get:
telnet> open 120.200.100.111 80
Trying 120.200.100.111...
Connected to foo.bar.org.
Escape character is '^]'.
Please note I am aware that for a full application I should use some sort of existing API for socket communications, but shouldn't the above test be getting some sort of timely response from the server?

shouldn't the above test be getting some sort of timely response from the server?
No. A Telnet exchange doesn't start with the server sending you anything. You have to send something. The server is waiting for you; you are waiting for it; you're the one with the read timeout, so you get a read timeout.
The Telnet client doesn't use read timeouts by default.

Related

Keep TCP socket-connection alive if no data is currently available

I have implemented a small HTTP-server which allows clients to connect via HTTP and stream audio-data to them.
My problem is, that in case there's currently no audio-data available, the connection seems to break, either because the client is disconnecting, or due to another reason inside Android.
I'm acting like the following way:
serverSocket = new ServerSocket(0);
Socket socket = serverSocket.accept();
socket.setKeepAlive(true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
out.write("HTTP/1.1 200 OK\r\n");
out.write("Content-Type: audio/wav\r\n");
out.write("Accept-Ranges: none\r\n");
out.write("Connection: keep-alive\r\n"); // additionally added due to answer below
out.write("\r\n");
out.flush();
..
while(len=otherInput.read(audioBuffer)){
out.write(audioBuffer, 0, len);)
}
For sure this is just a snipped of the real code, but it shows what I'm doing.
Now, in case the "otherinput.read()" takes a long time because there's no data available at the moment, I get a
java.net.SocketException: sendto failed: EPIPE (Broken pipe)
at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:499)
at libcore.io.IoBridge.sendto(IoBridge.java:468)
at java.net.PlainSocketImpl.write(PlainSocketImpl.java:508)
at java.net.PlainSocketImpl.access$100(PlainSocketImpl.java:46)
at java.net.PlainSocketImpl$PlainSocketOutputStream.write(PlainSocketImpl.java:270)
at java.io.BufferedOutputStream.flushInternal(BufferedOutputStream.java:185)
at java.io.BufferedOutputStream.write(BufferedOutputStream.java:139)
Who can tell me how I can prevent the connection from breaking/closing without a manual heartbeat? Do I miss some header or am I using something the wrong way?
Thanks for your help in advance, tried and searched myself crazy meanwhile.
There are at least two problems here.
Clients of HTTP servers are not well-behaved in the way you seem to expect. Consider a browser. The user can shut it down, go back, navigate away etc, any time he likes, even in the middle of a page load. If you get any error transmitting to the client there's nothing you can do except close the connection and forget about it. Same applies to any server really, but it applies unsolder to HTTP servers.
You're not reading the entire request sent by the client. You need to read all the headers until a blank line, then you need to read the body up to the length specified in the Content-length: header, or all the chunks, or until end of stream, as the case may be: see RFC 2616. The effect of this may be that you cause the behaviour at (1).

Two Producers send data simultaneously

I have a producer sending data for 15 seconds. I just replicate the same program and run it from different window while the first producer is already running. I get "Port 3333 already in use, java.net.BindException: Address already in use"
How can I make multiple producers (multi-process not threaded) send data at the same socket? However I dont know from where the port 3333 comes into picture.
What might be wrong with my program? I can provide the complete problem statement if desired. However in short I am using custom Kafka Producer to send data and I want two such Kafka Producers to send data.
I guess the program that you are starting is trying to listen for connections on a fixed port 3333, and when you start second instance it gives error of "Already Bound". See if there is a way to change that port using some arguments. But I cannot comment on that as you have not provided any source.
But I am just going to explain how things work in normal scenarios
Suppose consumer is listening on port 3333, then it will become the server and accept the connections on that port. And multiple clients can send data on that port to server
Sample Client Program
BufferedReader inFromUser = new BufferedReader( new InputStreamReader(System.in));
Socket clientSocket = new Socket("localhost", 3333); //3333 is the port on which the server is listening
DataOutputStream outToConsumer = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromConsumer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); //Only if consumer sends something in reply
sentence = inFromUser.readLine();
outToServer.writeBytes(sentence + '\n');
modifiedSentence = inFromConsumer.readLine();
So multiple producers will be clients and send data to consumers who are listening on dedicated ports. Keep in mind multiple consumers will not be able to listen on same socket,
you will have to use different ports for different consumers.
If you have a connection-oriented protocol (e.g. TCP) the server usually only listens for connections on the advertised port. When a client connects, the server's accept call results in a connection on effectively a random other port number, allowing the main server thread/process to continue listening for new connections on the advertised port.
With a datagram-based protocol (e.g UDP) this isn't an issue because no client maintains a persistent connection.
Either solution could work for you--which one to prefer depends on the nature of the traffic.

What is the reason for Broken Pipe on Unix Domain Sockets?

I have a server application which received requests and forwards them on a Unix Domain Socket. This works perfectly under reasonable usage but when I am doing some load tests with a few thousand requests I am getting a Broken Pipe error.
I am using Java 7 with junixsocket to send the requests. I have lots of concurrent requests, but I have a thread pool of 20 workers which is writing to the unix domain socket, so there is no issue of too many concurrent open connections.
For each request I am opening, sending and closing the connection with the Unix Domain Socket.
What is the reason that could cause a Broken Pipe on Unix Domain Sockets?
UPDATE:
Putting a code sample if required:
byte[] mydata = new byte[1024];
//fill the data with bytes ...
AFUNIXSocketAddress socketAddress = new AFUNIXSocketAddress(new File("/tmp/my.sock"));
Socket socket = AFUNIXSocket.connectTo(socketAddress);
OutputStream out = new BufferedOutputStream(socket.getOutputStream());
InputStream in = new BufferedInputStream(socket.getInputStream()));
out.write(mydata);
out.flush(); //The Broken Pipe occurs here, but only after a few thousand times
//read the response back...
out.close();
in.close();
socket.close();
I have a thread pool of 20 workers, and they are doing the above concurrently (so up to 20 concurrent connections to the same Unix Domain Socket), with each one opening, sending and closing. This works fine for a load test of a burst of 10,000 requests but when I put a few thousand more I suddenly get this error, so I am wondering whether its coming from some OS limit.
Keep in mind that this is a Unix Domain Socket, not a network TCP socket.
'Broken pipe' means you have written to a connection that had already been closed by the other end. It is detected somewhat asynchronously due to buffering. It basically means you have an error in your application protocol.
From the Linux Programmer's Manual (similar language is also in the socket man page on Mac):
The communications protocols which implement a SOCK_STREAM ensure that data is not lost or duplicated. If a piece of data for which the peer protocol has buffer space cannot be successfully transmitted within a reasonable length of time, then the connection is considered to be dead. When SO_KEEPALIVE is enabled on the socket the protocol checks in a protocol-specific manner if the other end is still alive. A SIGPIPE signal is raised if a process sends or receives on a broken stream; this causes naive processes, which do not handle the signal, to exit.
In other words, if data gets stuck in a stream socket for too long, you'll end up with a SIGPIPE. It's reasonable that you would end up with this if you can't keep up with your load test.

to read the packet of bytes on client(client Socket) from server(ServerSocket) using java

i m a new .
i m a java developer(fresher) and currently i m working on BSE project and i m facing problem to read the packet of bytes on the client(client socket) from the server(server socket). if u can help me then please help me.
Thanks in advance
Well, if you want to interact directly with packets, then you need to use a DatagramSocket instead of the regular Socket and ServerSocket.
Then, you should visit this link to see a good tutorial on how to get started with sending and receiving individual packets.
The basic idea is that the Client or Server will block on the recieve() call while it waits for its partner to send a packet using send().
If you aren't interested in the individual packets like you indicated in your question, then you will want to use Socket and ServerSocket. The first step to communicating between the two involves code that will look similar to the following:
//Server
// this call will block until the client tries to connect to the server
Socket cientConn = new ServerSocket(8878).accept();
// now you can use the connection's input and output streams to send data
/******************/
// Client
Socket serverConn = new Socket(addressOfServer, 8878);
// now you can use the connections input and output streams
After you get connections set up, you will have basically 2 read/write loops. One on the client, and one on the server.
while(true) [
// check for data from an input stream
...
// respond with message back
}
You will need a similar loop for the client and the server.

How can I force the server socket to re-accept a request from a client?

For those who do not want to read a long question here is a short version:
A server has an opened socket for a client. The server gets a request to open a socket from
the same client-IP and client-port. I want to fore the server not to refuse such a request but to close the old socket and open a new one. How can I do ti?
And here is a long (original) question:
I have the following situation. There is an established connection between a server and client. Then an external software (Bonjour) says to my client the it does not see the server in the local network. Well, client does nothing about that because of the following reasons:
If Bonjour does not see the server it does not necessarily means that client cannot see the server.
Even if the client trusts the Bonjour and close the socket it does not improve the situation ("to have no open socket" is worser that "to have a potentially bad socket").
So, client do nothing if server becomes invisible to Bonjour. But than the server re-appears in the Bonjour and Bonjour notify the client about that. In this situation the following situations are possible:
The server reappears on a new IP address. So, the client needs to open a new socket to be able to communicate with the server.
The server reappears on the old IP address. In this case we have two subcases:
2.1. The server was restarted (switched off and then switched on). So, it does not remember the old socket (which is still used by the client). So, client needs to close the old socket and open a new one (on the same server-IP address and the same server-port).
2.2. We had a temporal network problem and the server was running the whole time. So, the old socket is still available for the use. In this case the client does not really need to close the old socket and reopen a new one.
But to simplify my life I decide to close and reopen the socket on the client side in any case (in spite on the fact that it is not really needed in the last described situation).
But I can have problems with that solution. If I close the socket on the client side and than try to reopen a socket from the same client-IP and client-port, server will not accept the call for a new socket. The server will think that such a socket already exists.
Can I write the server in such a way, that it does not refuse such calls. For example, if it (the server) sees that a client send a request for a socket from the same client-IP and client-port, it (server) close the available socket, associated with this client-IP and client-port and than it reopens a new socket.
You can't "reopen" a socket on your server. If the socket already exists and the client is trying to reconnect then you should get an BindException (see your previous question). The scenario that may be possible:
Client Shuts down socket
Server OS "notices" socket is dead on client side and shuts its side down
Client reconnects on the same port, but with a "new" socket
In this case you may consider it be the "same" socket, but it really isn't. That said a strategy you may wish to adopt is to have some sort of map (hash of client IP/port) to whatever mechanism you are using to service the socket or some kind of persistent state data, so that it can simulate a continuation of a previous socket (in the same vein as http sessioning). Something along the lines of:
HashMap<Client, State> sessions = ...;
public void server(){
...
while(true){
Socket socket = server.accept();
Client client = new Client(socket);
State s = sessions.get(client);
if(s == null){
s = new State();
sessions.put(client, s);
}
client.setState(s);
service(client);
}
...
}
and you can adjust the map lookup to define what a "session" means within your application (same client IP, same client IP & client port, some sessionid sent over the wire, etc).
If you are just trying to make it possible for the client to reconnect and force the server to "notice" the client is disconnected, the only real way in Java is to try and read/write data, and if it has been shutdown then it should throw an exception. Therefore as was mentioned in your other question you could add some kind of ack/nak feature to your protocol and add some type of check if you believe the client is disconnected (for example if you haven't read any data in the last N milliseconds, send a message the client must echo within M milliseconds, otherwise it is assumed to be disconnected). You can also try isConnected, isInputShutdown, isOutputShutdown, but I have found those to be unreliable in my own code to indicate the socket state, unless you have closed the socket (i.e. the one you are testing on the server).
The situation you describe is impossible. You can't get a new connect request from the same remote IP:port as an existing connection. The client will not permit it to occur.
Based on the comments:
You cannot write the server in a way that it will close a socket it still thinks is connected and automatically accept the new connection, as application code does not have that kind of control over the TCP stack, nor is there a way to reopen a connection.
The chance of the port numbers being the same between your client restarts is very small.
But still, if that happens, the server will note that that you're trying to set up an already connected socket, and refuse your new connection. There's not much else your client can do in this case besides close your socket, create a new one and try to connect again - and another random port will be selected.
additional note, your server should take some form of action to detect and close dead sockets, if all your server does is read incoming data, the "dead" sockets will never be
closed as they will never be detected as dead.(enabling tcp keepalive is one cheap measure to take against dead sockets staying up for months, though it will take a couple of hours to detect them as such by default.)

Categories