I have trouble with the Java Sockets.
I need to connect a server and a client through the local network and as there can be more then two devices connected to the router the Client must find out the Address of the server.
The only way I know to solve this problem is to get the three first numbers of the clients IP(v4)-address and loop every of the 254 other possible IPs.
(I know that this way is very slow and may cause many problems. If you know an alternative, I will be glad).
Actually the client is an android smartphone so I can get the DHCP-Info.
The problem is, that the read command to check if a device is a server will last forever.
If you need some code, here it is!
code:
onCreate:
final WifiManager manager = (WifiManager) super.getSystemService(WIFI_SERVICE);
final DhcpInfo dhcp = manager.getDhcpInfo();
final String address = intToIp(dhcp.ipAddress);
String addresspart=address.substring(0, address.lastIndexOf('.')+1);
ArrayList<HashMap<String, String>> l = null;
Log.d("Keyboard","initiating search");
try {
l = new checkConnections().execute(addresspart).get();
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (ExecutionException e1) {
e1.printStackTrace();
}
checkConnections:
ArrayList<HashMap<String,String>> l=new ArrayList<HashMap<String,String>>();
for(int i=1;i<=255;i++){
try {
worksocket=new Socket(addresspart[0]+i,61927);
workout=new BufferedOutputStream(worksocket.getOutputStream());
workin=new BufferedInputStream(worksocket.getInputStream());
byte[] buffer=new byte[6];
workin.read(buffer);//at this point the app freezes until you stop the serverside program
String answer=new String(buffer,"UTF-8");
Log.i("Keyboard","Welcome Message: "+answer);
if(answer.equalsIgnoreCase("sdk on")){
HashMap<String,String> hm=new HashMap<String,String>();
hm.put("address",addresspart[0]+i);
l.add(hm);
workout.write(intToBytes(8));
workout.write("closing".getBytes("UTF-8"));
worksocket.close();
continue;
}
else{
Log.d("Keyboard","No SDK-Programm detected");
worksocket.close();
continue;
}
} catch (UnknownHostException e) {
Log.d("Keyboard",addresspart[0]+i+" doesn't exists");
continue;
} catch ( InterruptedIOException e){
Log.w("System.warn",e.getCause()+e.getLocalizedMessage());
Log.d("Keyboard","timeout");
continue;
} catch (IOException e) {
Log.d("Keyboard",addresspart[0]+i+" doesn't exists");
e.printStackTrace();
continue;
}
}
return l;
the server's code:
ServerSocket serverSocket = new ServerSocket(61927);
System.out.println("Socket initiated");
Socket client = serverSocket.accept();
BufferedInputStream in=new BufferedInputStream(client.getInputStream());
BufferedOutputStream out=new BufferedOutputStream(client.getOutputStream());
System.out.println("client found");
byte[] buffer=new byte[11];
out.write("sdk on".getBytes("UTF-8"));
in.read(buffer);
String s=new String(buffer,"UTF-8");
if(!s.equals("got info")){
System.out.println("No SDK Client");
client.close();
serverSocket.close();
new Main();
}
Uh, I think I should ping the Broadcast-IP and listen for answers instead...
Android's Linux runtime allows it to read from which IP an answer is coming.
Related
in Java, using Socket to connect into server with the following code will probably generate an error of java.net.ConnectException: Connection refused: when the server is down or not yet started.
try {
Socket clientSocket = new Socket(SERVER_IP, PORT);
} catch (IOException e) {
e.printStackTrace();
}
what is the best way to handle this exception? how do you continue trying to connect until server become available without having this issue?
UPDATE:
my method is to use UDP, send message into given port and then wait for a response in a given time, loop until I get a response before starting the socket.
I'm looking for a better approach.
What about something along these lines:
String SERVER_IP = "ip";
int PORT = 0;
int maxTries = 10;
int timeBeforeRetry = 5000; //ms
int count = 0;
Socket clientSocket = null;
while(clientSocket == null && count < maxTries) {
try {
clientSocket = new Socket(SERVER_IP, PORT);
} catch(IOException e) {
// Log if you want
try {
Thread.sleep(timeBeforeRetry);
} catch(InterruptedException e) { /* can be ignored or logged I guess */ }
}
count++;
}
if(clientSocket == null) {
// throw some kind of exception
}
I have a 2 nodes that should always communicate with each other, but they don't seem to talk for more than 1 interaction. After successfully sending and receiving 1 message, they stop.
My code looks like this:
The initiator:
try {
Socket client = new Socket(ip, port);
OutputStream toNode = client.getOutputStream();
DataOutputStream out = new DataOutputStream(toNode);
out.writeUTF("Start:Message");
System.out.println("Sent data");
InputStream fromNode = client.getInputStream();
DataInputStream in = new DataInputStream(fromNode);
if(in.readUTF().equals("Return Message")) {
System.out.println("Received data");
out.writeUTF("Main:Message");
System.out.println("Sent data again");
}
else
System.out.println("Error");
client.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
The responder:
while(true) {
Socket server;
try {
server = s.accept();
DataInputStream in = new DataInputStream(server.getInputStream());
String msg = in.readUTF();
String[] broken_msg = msg.split(":");
if(broken_msg.length > 0)
System.out.println("Looping");
String ret;
if (broken[0].equalsIgnoreCase("Start")) {
ret = "Return Message";
DataOutputStream out = new DataOutputStream(server.getOutputStream());
out.writeUTF(ret);
}
else if (broken[0].equalsIgnoreCase("Main")) {
//Do Useful work
}
} catch (IOException e) {
e.printStackTrace();
}
}
My output looks like this:
Looping
and:
Sent data
Received data
Sent data again
You are looping around the accept() call, accepting new connections, but your actual I/O code only reads one message per connection. You need an inner loop around the readUTF() calls, handling the entire connection until EOFException is thrown. Normally all the I/O for a connection is handled in a separate thread.
In order for programs to do repetitive actions, you would generally use looping of some sort, including for loops, while loops and do-while loops. For something like this where you don't know how many times you'd need to communicate in advance, then you would need to use a while loop, not a for loop.
Having said that, you have no while loops whatsoever inside of your connection code... so without code that would allow continued communication, your program will stop, exactly as you've programmed it to do.
Solution: fix this. Put in while loops where continued communication is needed.
I'm working on a java server-client based file transfer over socket project, I'll sum up the project shortly, I have text files related to server and client, server related text contains which ports are going to be opened and client text contains the IP and port to be connected on(server side is like 4444 and client side is like 4444 localhost) The file transfer on a single client is running pretty ok, now I'm working on second client connection and transfer, what I'm trying to do is; when a second client is run, it will read the first line of the text file (which is already in use by the first client), I thought a recursion will solve the problem but seems I couldn't figure out what I've done wrong, below are the code snippet from client side
boolean connected = false;
private void connection() {
while (!connected) {
try {
FileReader fr = new FileReader("c_input.txt");
BufferedReader br = new BufferedReader(fr);
String line = br.readLine();
String delims = "[ ]";
String[] elements = new String[8];
elements = line.split(delims);
serverPort = Integer.parseInt(elements[portIndex]);
hostIP = elements[ipIndex];
clientSocket = new Socket(hostIP, serverPort);
is = clientSocket.getInputStream();
if (is != null) {
connected = true;
System.out.println("connected to " + hostIP + " from port "
+ serverPort);
br.close();
fr.close();
} else {
System.out.println("The port " + serverPort
+ " is occupied, now trying another port.");
portIndex = portIndex + 2;
ipIndex = ipIndex + 2;
connection();
}
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
System.exit(0);
}
}
}
I used recursion there, because if a port is bound by another client it has to read another line from text file and split and retry connection with the new line's inputs.(in terms short the whole method will run again) But when it comes to running, the first client connects and when second one tries to connect from same port with client1 the code still gets in if loop instead of getting in else block (I get the message from the if check's println on the console and by the way is in the if check stands for InputStream) which means there is a stream coming from server, is this normal? if so how can I achieve the whole thing connection method does all over again if the port is bound by another client?
I wrote a simple program where a server should print data sent by multiple clients. But the server receives only partial data. Following are the relevant pieces of the code.
Server:
try {
serverSocket = new ServerSocket(8888);
} catch (IOException e) {
System.err.println("Could not listen on port: 8888");
System.exit(-1);
}
while (listening) {
Socket clientSocket = serverSocket.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
System.out.println(reader.readLine());
reader.close();
clientSocket.close();
}
serverSocket.close();
Client:
try {
socket = new Socket("nimbus", 8888);
writer = new PrintWriter(socket.getOutputStream(), true);
localHost = InetAddress.getLocalHost();
}
catch (UnknownHostException e) {}
catch (IOException e) {}
StringBuilder msg1 = new StringBuilder("A: ");
for(int i=1; i<=3; i++)
msg1.append(i).append(' ');
writer.println(localHost.getHostName() + " - " + msg1);
StringBuilder msg2 = new StringBuilder("B: ");
for(int i=4; i<=6; i++)
msg2.append(i).append(' ');
writer.println(localHost.getHostName() + " - " + msg2);
StringBuilder msg3 = new StringBuilder("C: ");
for(int i=7; i<=9; i++)
msg3.append(i).append(' ');
writer.println(localHost.getHostName() + " - " + msg3);
writer.close();
socket.close();
I get the following output (when run on 3 clients)
nimbus2 - A: 1 2 3
nimbus3 - A: 1 2 3
nimbus4 - A: 1 2 3
I don't get the second and third messages. Server keeps waiting. Where am I going wrong?
Edit: In the server code, I tried removing reader.close() and clientSocket.close(). That didn't work either. Another question -- if 3 clients send 3 messages, does it require 9 connections? (this is the reason, I closed the connection in the server code)
You probably want to be delegating the handing of the socket to another thread. I've written up an example that works by passing each incoming socket to an Executor so it can read all the inputs. I use a Executors.newCachedThreadPool() which should grow to be as big as needed. You could also use Executors.newFixedThreadPool(1) if you want it to only be able to handle 1 client at a time.
The only other change I made was I removed the BufferedReader and replaced it with a Scanner. I was having issues with the BufferedReader not returning data. I'm not sure why.
Executor exe = Executors.newCachedThreadPool();
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8888);
} catch (IOException e) {
System.err.println("Could not listen on port: 8888");
System.exit(-1);
}
while (listening) {
final Socket clientSocket = serverSocket.accept();
exe.execute(new Runnable() {
#Override
public void run() {
try {
Scanner reader = new Scanner(clientSocket.getInputStream());
while(reader.hasNextLine()){
String line = reader.nextLine();
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
serverSocket.close();
It looks like you close the connection to the client before they can finish writing/before the server reads all of the messages they sent. I think you need to continue to readline, and potentially not terminate the client's connection after they send you one message.
John is right.
you close the client connection by calling clientsocket.close() after reading the message that is why you cannot get the other messages. you should call clientsocket.close() when you have received all the messages
It seems to me that there is some kind of limitation in socket creation in MIDP.
I need to make lots of connections to a server (none concourrent) and in the forth or fith try my app crashes. It crashes in the simulator and in my real device as well.
To isolate any possibility of it being influenced by my code, I isolated the following code:
try {
StreamConnection c;
StringBuffer sb = new StringBuffer();
c = (StreamConnection) Connector.open(
"http://www.cnn.com.br/", Connector.READ_WRITE);
InputStreamReader r = new InputStreamReader(c.openInputStream(), "UTF-8");
System.out.println(r.read());
c.close();
} catch (IOException ex) {
ex.printStackTrace();
}
This code crashes in the 13th try.
I've tryed to add a sleep of 10 seconds inside a while loop and, it crashes at the 13th try too.
The crash message is:
java.io.IOException: Resource limit exceeded for TCP client sockets
- com.sun.midp.io.j2me.socket.Protocol.open0(), bci=0
- com.sun.midp.io.j2me.socket.Protocol.connect(), bci=124
- com.sun.midp.io.j2me.socket.Protocol.open(), bci=125
While c.close() inside the try should be adequate, I am wondering if you have other issues that are triggering this. The code really should be closing the connection AND inputstream inside of a finally. Something like this:
StreamConnection c = null;
InputStream is = null;
try {
StringBuffer sb = new StringBuffer();
c = (StreamConnection) Connector.open(
"http://www.cnn.com.br/", Connector.READ_WRITE);
is = c.openInputStream();
InputStreamReader r = new InputStreamReader(is, "UTF-8");
System.out.println(r.read());
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (Exception ex) {
System.out.println("Failed to close is!");
}
}
if (c != null) {
try {
c.close();
} catch (Exception ex) {
System.out.println("Failed to close conn!");
}
}
}
The reason, why the c.close() did not actually close was because the inputstream was not closed. Some devices require that both the stream and the connection be closed. Also the connections do not close immediately, on some devices, when the close() method is called. You might have to do a gc too