Reusing sockets in server-client - java

I am trying to create a client-server system: my server is a raspberry pi which is running a python webserver on it, and my client is on a different pc and is written is Java. The idea is that the server collects data and when it gets a request from a client, it sends the data to the client.
My client should request the data, wait for 10 seconds and request again etc.
Currently this system is working, but after a day or so, the client starts getting a lot (but not continuously) socket timeouts. I think that this may be the case because for each request I create a new socket for communication and I think that after a day the sockets run out or something like that. This is the code the client executes every 10 seconds:
public static String getData() throws Exception {
TreeSet<Integer> primes = MathUtils.primesSieve(10000);
try {
String data = "";
Socket socket = new Socket(SERVER_ADDRESS, SERVER_PORT);
socket.setReuseAddress(true);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
int msg = ColUtils.drawRandomlyWithReplacement(primes, 1, ArrayList::new).get(0);
out.write(msg+"");
out.flush();
String input;
while ((input = in.readLine()) != null) {
data += input;
if (!data.endsWith("#" + prod(msg))) {
throw new Exception("WRONG ECHO");
}
}
socket.close();
return data;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
I tried fixing it by having a socket which is a member of the encapsulating class, but after a singe request the inputstream stopped working. Is there any way where I can keep using a single socket for ALL communications with the server? Or is this the recommended way of doing this sort of communication?

Try first closing the socket and input, output streams. As in your code there is no quarantee that you are releasing the acquired objects.
PrintWriter out = null;
BufferedReader in = null;
Socket socket = null;
try {
...//your statements
} catch (Exception ex) {
//catch or whatever
} finally {
if (out != null) out.close();
if (in != null) in.close();
if (socket != null) socket.close();
}

try to make the Socket object static If possible that would created only once and read the data every 10 sec
Otherwise u can instantiate it before calling the getData method and then read it.
Doing so will make only 1 copy of Socket.
And I don't think u are running out of ports.
The reason might be quit simple that your Program is not receiving the data before the time out. and it is a normal case in a bad network
Socket generally waits indefinitely until it receives data if the timeout is not set Programmatically

Related

Unresponsive socket read buffer

I am trying to send data to one of my servers and receive an ACK back from it. However, the processing gets hung up when waiting for a response from the server. I know for a fact that there is a connection because I can see the data reaching the server. I also know that the server is outputting data correctly because my C# client is receiving data back from the server. I will note that this client is running on a centOS virtual machine. The server is a remote windows machine. I wouldn't imagine that there would be an issue due to the virtual environment because I am able to use an SNMP java client (SNMP4j package) to make calls to a remote server. I believe my server is outputting raw binary too, but I would expect to see some kind of output either way.
// A Java program for a Client
import java.net.*;
import java.io.*;
public class Client
{
// initialize socket and input output streams
private Socket socket = null;
private DataInputStream input = null;
private DataOutputStream out = null;
private DataInputStream serveroutput= null;
// constructor to put ip address and port
public Client(String address, int port)
{
// establish a connection
try
{
socket = new Socket(address, port);
System.out.println("Connected");
// takes input from terminal
input = new DataInputStream(System.in);
// sends output to the socket
out = new DataOutputStream(socket.getOutputStream());
serveroutput = new DataInputStream(socket.getInputStream());
}
catch(UnknownHostException u)
{
System.out.println(u);
}
catch(IOException i)
{
System.out.println(i);
}
// string to read message from input
String line = "";
// keep reading until "Over" is input
while (!line.equals("Over"))
{
try
{
line = input.readLine();
out.writeUTF(line);
System.out.println(serveroutput.readLine())
}
catch(IOException i)
{
System.out.println(i);
}
}
// close the connection
try
{
input.close();
out.close();
socket.close();
}
catch(IOException i)
{
System.out.println(i);
}
}
Could be great if you would share the otherside codes. (sorry cannot comment yet)
Try use something else over writeUTF(), simply maybe a PrintStream, as mentioned by #marquis-of-lorne (read|write)UTF may be confusing by the peer.
Also this might be a good practice to flush() out the output from both side when there is nothing else to send to make sure data is sent completely.
You may also try BufferedReader over InputDataStream as you are trying to read lines. readLine() from InputDataStream is deprecated.

html5 audio GET connection reset by peer on mobile (works fine on PC)

What I'm trying to do is simply send an mp3 file over http/tcp with my own http headers. On the client side I have a webpage with the following line:
<audio src="http://192.168.0.21:14441" controls autoplay loop>
The Java server side has a ServerSocket and accepts basically any connection. It will then send a hardcoded http header followed by the binary data of the mp3-file.
My server class:
public class Server {
private int port = 14441;
private String localIPAddress;
private BufferedReader in;
private BufferedOutputStream out;
private ServerSocket serverSocket;
private Socket clientSocket;
public Server() {
}
public void start() {
new Thread(new Runnable() {
#Override
public void run() {
startAcceptingConnections();
}
}).start();
}
private void startAcceptingConnections() {
tryToOpenPort();//try to open external port with upnp
clientSocket = null;
try {
serverSocket = new ServerSocket(port);
} catch (IOException e) {
System.err.println("Could not listen on port:" + port);
System.exit(1);
}
System.out.println("Waiting for connection.....");
try {
clientSocket = serverSocket.accept();
System.out.println("Connection successful");
System.out.println("Waiting for input.....");
out = new BufferedOutputStream(clientSocket.getOutputStream());
in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
boolean isSendingMp3 = false;
while ((inputLine = in.readLine()) != null) {
//just output any line the client sends me
System.out.println("Received: " + inputLine);
//Whenever the client sends an empty line this means
//it's ready to receive
if (inputLine.equals("") && !isSendingMp3) {
isSendingMp3 = true;
//Making sure to keep listening to the InputStream
//so I send from a different thread
new Thread(new Runnable() {
#Override
public void run() {
sendMp3File();
}
}).start();
}
}//end of listening to client loop
out.close();
in.close();
clientSocket.close();
serverSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private void sendMp3File() {
try {
//I've tried all sorts of headers
String response = "HTTP/1.x 200 OK\r\n"
+ "Content-Type: audio/mpeg\r\n"
+ "Content-Size: 2911084\r\n"
+ "Range: bytes 0-2911083/2911084\r\n"
+ "X-Content-Duration: 300.1\r\n"
+ "Connection: keep-alive\r\n"
+ "Content-Duration: 300.1\r\n"
+ "\r\n";
out.write(response.getBytes(Charset.forName("UTF-8")));
byte[] bytesRaw = new byte[1024 * 10];
InputStream is = new FileInputStream("C:/sample.mp3");
int byteCount = 0;
while ((byteCount = is.read(bytesRaw)) != -1) {
System.out.println("sending bytes:" + byteCount);
out.write(bytesRaw, 0, byteCount);
}
out.flush();
is.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
//Use Cling to open the port via upnp
private void tryToOpenPort() {
try {
localIPAddress = Inet4Address.getLocalHost().getHostAddress();
PortMapping desiredMapping
= new PortMapping(
port,
localIPAddress,
PortMapping.Protocol.TCP,
"Test server"
);
UpnpService upnpService = new UpnpServiceImpl(new PortMappingListener(desiredMapping));
upnpService.getControlPoint().search();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
This always works on a PC browser (Firefox, Chrome, IE) and gives no problems machine to machine (no firewall interference).
However, as soon as I run the webpage from a mobile device (both iOS and Android) the connection is suddenly closed after sending what seems to be a random amount of data. This is somewhere between 0 and 2 seconds after the connection has been established.
The Java application throws the exception:
java.net.SocketException: Connection reset by peer: socket write error
When I profile with Wireshark it shows me everything goes well and then suddenly the client starts sending a bunch of RST messages. I've tried multiple types of headers, even copied a number of headers from existing webservers, but nothing seems to work.
Even simple headers like
"HTTP/1.1 200 OK\r\n"
+ "Content-Type: audio/mpeg \r\n"
+ "\r\n";
Work when I open them from a computer browser, but reset the connection on mobile. Am I forgetting something important?
UPDATE
On mobile browsers it closes the connection after a bit of data has been send. It connects and disconnects again at what seems like random intervals, sometimes with a range in the header and sometimes not. Even when it has received the entire file it will continue to open connections.
I'm guessing some sort of high protocol 'protection' when sending big requests, maybe specifically for when on unstable mobile networks.
Is there some way to bypass this? Whatever it is, it seems a bit unduly.
What happens is that the html5 audio element asks for the first 2 bytes with a range header. When I then (according to rfc2616 validly) ignore this range and send the whole file, the audio player starts behaving as if it's an audio stream (or at-least becomes very confused). This still only happens on mobile browsers somehow.
The solution might be to start accepting range request so that the player doesn't get "confused". I'll post the results as soon as I get the time to try this.
I think the problem is in the code you have not shown. My guess is that you accept the connection and then simple send the response without reading the request. But if the connections gets closed with the request not read this will cause a connection reset. How this reset affects the client depends on the timing, i.e. it might be that the client processed the response before it got the reset or that it found the reset before it had time to process the response.
To fix it you need to read the HTTP request before you sent the response.

read socket data with java

i'm using websocket to send data, this is the code (javascript)
socket= new WebSocket('ws://localhost:10302/socket');
socket.onopen= function() {
socket.send('delete structure'+c);
}
in the server side i'm using java and this is the code
try {
standardiste = new ServerSocket(10302);
while(true) {
System.out.println("listening data from socket");
socket = standardiste.accept();
try {
BufferedReader entree = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(entree!=null)
{
System.out.println(entree.readLine());
}
}
catch(IOException exc) {
}
socket.close();
}
}
i want to read the data sended ?
What you need is
String line;
while((line = entree.readLine()) != null){
System.out.println(line);
}
What you were trying was to tie in the BufferedReader into the Socket, but never read anything from it. That's where the BufferedReader.readLine() method comes in, which reads a single line (until it reaches an endline character) from the buffer.
By comparing the current line to null (readLine() != null) you keep reading until it stops receiving the end of a transmission.
Edit:
I'm afraid the WebSocket protocol is different from the Java Socket protocol, hence it receives just the headers, but doesn't recognize any of the actual data that is being sent, simple because the protocols don't match up. Try using the Java WebSocket class. Here is a good tutorial.

How to exit/disconnect from telnet properly?

Im telneting into a server and it will block the port if I do not disconnect properly. Im already using socket.close(); so I am not sure what I am doing wrong to disconnect completely from the server
//java socket client example
import java.io.*;
import java.net.*;
public class socket_client {
public static void main(String[] args) throws IOException {
Socket s = new Socket();
String host = "1.1.1.1";
PrintWriter s_out = null;
BufferedReader s_in = null;
try {
s.connect(new InetSocketAddress(host, 12656));
System.out.println("Connected");
// writer for socket
s_out = new PrintWriter(s.getOutputStream(), true);
// reader for socket
s_in = new BufferedReader(new InputStreamReader(s.getInputStream()));
}
// Host not found
catch (UnknownHostException e) {
System.err.println("Don't know about host : " + host);
System.exit(1);
}
// Send message to server
String message = "this is the msg";
s_out.println(message);
System.out.println("Message send");
// Get response from server
String response;
while ((response = s_in.readLine()) != null) {
System.out.println(response);
}
// close the socket
s.close();
// close the i/o streams
s_out.close();
s_in.close();
}
}
There is no disconnect sub-protocol in Telnet. All you have to do is close the socket.
I've never seen or heard of a Telnet server 'block a port if I do not disconnect properly'. I have a production Telnet client which does only that, and which has been working correctly for five or six years. And any server at all that doesn't handle unexpected disconnections properly has something very seriously wrong with it.
The problem is elsewhere, possibly in the (unspecified) server itself. To behave as you describe, it would have to completely ignore end of stream conditions, and ignore IOExceptions as well (or else treat them as completely fatal to the entire process). It would also have to be single-threaded. I'm finding it rather difficult to believe in the existence of such a server, or indeed this problem.
NB you only need to close 's_out', the outermost stream/writer you've wrapped around the socket output stream. If you must close the input stream and the socket, do so after closing the output stream/writer.
The socket is blocked since the server side is not handling unexpected socket closing. You have two alternatives - or rather, two steps, if you want to be thorough - to fixing this.
Handle the other end of the connection closing unexpectedly in an
exception handler, and closing the socket when needed.
Having the client send a message to the server when it wants to
close the connection, allowing the server to close the socket, and
then handling that closed socket as a successful operation.
This is an example of server socket code from O'Reilly that gracefully handles unexpected termination:
try {
ServerSocket server = new ServerSocket(5776);
while (true) {
Socket connection = server.accept( );
try {
OutputStreamWriter out
= new OutputStreamWriter(connection.getOutputStream( ));
out.write("You've connected to this server. Bye-bye now.\r\n");
connection.close( );
}
catch (IOException e) {
// This tends to be a transitory error for this one connection;
// e.g. the client broke the connection early. Consequently,
// we don't want to break the loop or print an error message.
// However, you might choose to log this exception in an error log.
}
finally {
// Most servers will want to guarantee that sockets are closed
// when complete.
try {
if (connection != null) connection.close( );
}
catch (IOException e) {}
}
}
catch (IOException e) {
System.err.println(e);
}

Checking for a client disconnect on a Java TCP server - output only

I have a Java TCP server which, when a client connects to it, outputs a message to the client every 30 seconds. It is a strict requirement that the client does not send any messages to the server, and that the server does not send any data other than the 30-second interval messages to the client.
When I disconnect the client, the server will not realise this until the next time it tries to write to the client. So it can take up to 30 seconds for the server to recognise the disconnect.
What I want to do is check for the disconnect every few seconds without having to wait, but I am not sure how to do this given that a) the server does not receive from the client and b) the server cannot send any other data. Would anyone please be able to shed some light on this? Thanks.
Even though your server doesn't "receive" from the client, a non-blocking read on the client socket will tell you that either there's nothing to be read (as you expect), or that the client has disconnected.
If you're using NIO you can simply use a non-blocking Selector loop (with non-blocking sockets) and only write on your 30 second marks. If a SelectionKey is readable and the read on the SocketChannel returns -1 you know the client has disconnected.
EDIT: Another approach with blocking is simply to select with a 30 second timeout. Any client disconnects will cause the select to return and you'll know which ones those are via the read set. The additional thing you'd need to do there is track how long you were blocked in the select to figure out when to do your writes on the 30 second mark (Setting the timeout for the next select to the delta).
Big Edit: After talking to Myn below, offering complete example:
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(1);
}
Socket clientSocket = null;
try {
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
// Set a 1 second timeout on the socket
clientSocket.setSoTimeout(1000);
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(
clientSocket.getInputStream()));
long myNextOutputTime = System.currentTimeMillis() + 30000;
String inputLine = null;
boolean connected = true;
while (connected)
{
try {
inputLine = in.readLine();
if (inputLine == null)
{
System.out.println("Client Disconnected!");
connected = false;
}
}
catch(java.net.SocketTimeoutException e)
{
System.out.println("Timed out trying to read from socket");
}
if (connected && (System.currentTimeMillis() - myNextOutputTime > 0))
{
out.println("My Message to the client");
myNextOutputTime += 30000;
}
}
out.close();
in.close();
clientSocket.close();
serverSocket.close();
}
Worth noting here is that the PrintWriter really moves you far away from the actual socket, and you're not going to catch the socket disconnect on the write (It will never throw an exception, you have to manually check it with checkError()) You could change to using a BufferedWriter instead (requires using flush() to push the output) and handling it like the BufferedReader to catch a disco on the write.
If you are managing multiple clients then I guess you would be using Non-Blocking sockets (If not then consider using Non-Blocking). You can use Selector to monitor all the connected sockets to check if they are readable or writeable or there is some Error on that socket. When some client disconnects, your Selector will mark that socket and will return.
For more help google "Socket Select function"

Categories

Resources