can't ping the same IP twice - android

I have written this code for pinging class C IP addresses on port 6789, the thread starts when I click on a button called PING. It will retrieve all IP addresses that has the port 6789 open. But what I need is to refresh (re-ping) every, let's say 5 seconds, and add IPs recently joined if exist and omit ones that leave the port. Unfortunately another issue appears. When I started the application the first iteration of the while (true) works perfectly, and it adds any IP that had the port 6789 open to the ArrayList ips_List and then display it on the ListView, and when another device joins the port, my phone will add it to the ips_List also. BUT in the second iteration after the Thread sleeps 5 seconds and then begins to re-ping the IPs from (x.x.x.1 - x.x.x.254) to see if another IP had joined the port when pinging to an IP previously pinged, the Socket will throw IOException (as written in the code).
Why is that happening?
Thread pingo = new Thread(new Runnable() {
public void run() {
while (true) {
if (readableNetmask.equals("255.255.255.0")) {
for (int i = 2; i <= 25; i++) {
String ip_address = readableIPAddress;
String oct1 = "", oct2 = "", oct3 = "", oct4 = "";
StringTokenizer stok = new StringTokenizer(
ip_address, ".");
while (stok.hasMoreTokens()) {
oct1 = stok.nextToken();
oct2 = stok.nextToken();
oct3 = stok.nextToken();
oct4 = stok.nextToken();
}
to_ping_ip = oct1 + "." + oct2 + "." + oct3
+ "." + String.valueOf(i);
if (pingAddress(to_ping_ip, 6789)) {
ips_List.add(to_ping_ip);
}
}
}
// delay 10 seconds, then re-ping
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
break;
}
handler.post(new UpdateIPListViewRunnable());
}
}
});
pingo.start();
PingAddress() function:
public boolean pingAddress(String ip, int port) {
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(ip, port), 200);
socket.close();
} catch (IOException e) {
return false;
}
return true;
}
List where addresses appear:
static public class UpdateIPListViewRunnable implements Runnable {
public void run() {
arrayAdapter.clear();
for (int i = 0; i < ips_List.size(); i++) {
arrayAdapter.add(ips_List.get(i));
arrayAdapter.notifyDataSetChanged();
}
ips_List.clear();
}
}

Your problem is likely in your atypical usage of the word "ping". Traditionally, this refers to sending an ICMP echo request, which does not involve connection state, but is also often not allowed to ordinary user IDs such as your application will run under.
You appear to be using a stateful TCP connection instead, and may be running into difficulty in if your server is not tuned to be able to accept rapid reconnects. So you may want to try testing your server using some other client. You could also have a problem in that TCP will keep trying to get the traffic through, so it won't quickly report network troubles. You may even be ending up with multiple attempts overlapping in time.
Your best solution though would probably be to switch from TCP, which is ill suited to this task, to UDP, which is probably a better match. UDP does not have connection state, and it's also unreliable in that no automatic retries are attempted. You should be able to find a UDB echo server and client type example with a web search.

Thank you #Chris Stratton ... and there is noway that I am changing to protocol to UDP since my project's structure is build over the TCP architecture ... now for my problem I finally FOUND the solution; in my app i have a ServerSocket that is used for pinging ... now considering there are two mobiles with the same app, if PING button clicked then it will ping the other device and and the other device will accept() the connection then close() it. Now on the first mobile it will iterates another time (while(true)) and ping the same device, but that device has the ServerSocket closed so it will returns false. For this is used a recursive thread that when a mobile 1 pings mobile 2, mobile 2 will close the ServerSocket and immediately calls the same thread so the ServerSocket is opened to other pings. I tried it and it worked very well :DDD
[#Experts: any enhancements for this solution!]
Recursive Thread:
static public class ReceivePingThread extends Thread {
public void run() {
try {
ServerSocket joinPort = new ServerSocket(6789, 100);
joinPort.accept();
joinPort.close();
ReceivePingThread ReceivePingThread = new ReceivePingThread();
ReceivePingThread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Related

Is the usage of TcpClients in unity3d for android possible?

I am trying to make an andorid app that commuicates with my server via Unity 5.4. The Devices need to be in the same network to do so.
For that i am using System.Net.Sockets and a TcpClient to connect to my server. Everything works well when i run it out of the Editor, or build it as a Windows standalone.The communication between a pc hosting the service and a diffrent pc running the standalone is possible and working as intended. As soon as i build it as an .apk and install it on my smartphone i will get a SocketException. Also my phone is stuck loading for quite some time
Is using a TcpClient, is that possible on android with unity3d ?
The Exception i get is:
System.Net.Sockets.SocketException: Connection timed out
I made sure that both devices are in the same network, e.g. the Ip for my Pc hosting the server is 192.168.178.24 and the ip for my smartphone is 192.168.178.113.
The ports required are open and the firewall lets data through.
I am runnig this code in Unity:
private TcpClient client;
private StreamWriter writer;
void Start()
{
try
{
client = new TcpClient(AddressFamily.InterNetwork);
IPAddress ipAddress = IPAddress.Parse(PlayerPrefs.GetString(MenuManager.IpPlayerPrefKey));
Debug.Log(ipAddress.ToString());
client.Connect(ipAddress, 11000);
writer = new StreamWriter(client.GetStream());
Debug.Log("connected");
}
catch (ArgumentNullException ane)
{
Debug.Log(string.Format("ArgumentNullException : {0}", ane.ToString()));
}
catch (SocketException se)
{
Debug.Log(string.Format("SocketException : {0}", se.ToString()));
}
catch (Exception e)
{
Debug.Log(string.Format("Unexpected exception : {0}", e.ToString()));
}
}
i double checked if the Ip adress recieved from the player prefs is correct, it is.
Has someone an idea what causes it to not even establish a connection ? I tried Wireshark on my pc, it didn't show any incoming packages, so my guess is the mistake is sometimes during establishing the connection.
Here is an image for my Log output from the smartphone:
LogCat Output
Edit: Server Code
public class ServiceListener
{
public TcpListener Listener;
public void StartListening()
{
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = Array.Find<IPAddress>(ipHostInfo.AddressList, ipMatch => ipMatch.AddressFamily == AddressFamily.InterNetwork);
Listener = new TcpListener(ipAddress, 11000);
Listener.Start();
}
public void StopListening()
{
Listener.Stop();
}
}
static void Main()
{
ServiceListener currentListener = new ServiceListener();
currentListener.StartListening();
TcpClient currentClient = currentListener.Listener.AcceptTcpClient();
StreamReader reader = new StreamReader(currentClient.GetStream());
Console.WriteLine("Connected");
while (true)
{
byte[] messageBytes = new byte[1024];
if (!reader.EndOfStream)
{
string message = reader.ReadLine();
string[] messageParts = message.Split('|');
int xOffset = int.Parse(messageParts[0]);
int yOffset = int.Parse(messageParts[1]);
bool leftClick = bool.Parse(messageParts[2]);
bool rightClick = bool.Parse(messageParts[3]);
Console.WriteLine(string.Format("x:{0},y:{1},left:{2},right:{3}", xOffset, yOffset, leftClick, rightClick));
}
else
{
currentClient = currentListener.Listener.AcceptTcpClient();
reader = new StreamReader(currentClient.GetStream());
}
}
}
Is using a TcpClient, is that possible on android with unity3d ?
Yes, it is. It is very possible and should work.
Your problem is very likely to come from this line of code:
IPAddress ipAddress = IPAddress.Parse(PlayerPrefs.GetString(MenuManager.IpPlayerPrefKey));
Since your hosting server IP is 192.168.178.24. Hardcode the value for testing purposes to see if PlayerPrefs.GetString(MenuManager.IpPlayerPrefKey) is returning an invalid IP Address.
Maybe something like:
IPAddress ipAddress = IPAddress.Parse("192.168.178.24");
Another thing to do in your server code is to put Application.runInBackground = true; in your Start() function. This will make sure that your server is running even when the Applciation is not on focus.
Finally, you are currently using synchronous server socket. When connecting, receiving data from the server, Unity will block/freeze until that operation completes. You should use asynchronous socket or run your server and client code in another Thread. This does not look like the current problem but you will run into it later on.

server socket multithreading confuses with the devices

I'm writing an Android app using sockets for communication. In a class called sever I accept clients (android devices) and open sockets for them.
Server side:
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Socket socket = serverSocket.accept();
Client clientThread = new Client(socket);
System.out.println("New client: " + clientThread.getName());
new Thread(clientThread).start();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
After a succesful connection the user may create a group, which is like a room for number of clients to connect and play together.
The group creation is done here:
Server side:
Client:
private void client_create() {
this.mGroup = new Group();
mGroup.joinPlayer(this);
System.out.println("New group for: " + name);
}
Group:
public Group(int nClients){
// Clients in this group
this.clients = new ArrayList<Client>();
}
public void joinPlayer(Client player){
clients.add(player);
}
Client Side:
Connection handling:
try {
socket = new Socket(hostName, portNumber);
out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
Listener listener = new Listener();
new Thread(listener).start();
} catch (IOException e) {
e.printStackTrace();
}
I ran this programm on 2 android devices and on my localhost as the server. After the connection was made, I tried creating 2 independent different groups. While debugging it all seems legit until I reached to a point where I lost it due to the 2 different running threads.
The odd thing that happened is that after the first group was created with the first client (clients contains the first device client object), and then the second group with the second player (clients contains the second device client object), the first group clients array contains the second client object (from the second device).
Have you got any thoughts on that? Did I do something wrong?
Figured it out.
Clients was mistakly defined as static, so I guess when accessing to the clients array of the static object it received the last one who was created.

Android client socket doesn't send data after some time

I'm developing an Android real-time-data app that sends data (floats and ints) to a server on the local subnet via a TCP socket. The problem I'm facing is that after sending some data simultaneously the socket doesn't send anymore data at all. I debugged the app and it shows that data is being sent but doesn't show up on the server. After this happens if I close the connection the server doesn't even get the notification that the connection has been terminated which it should according to my design model. Meanwhile I get an exception on the app saying it can not write to a broken pipe. This tells me that the problem is with the app because I also did test using a desktop app and I can send huge amounts of data to the server and it gets delivered.
And please keep in mind that the data size I'm talking about here is 252 bytes per packet.
Here's my class I'm using. (This runs in an AsyncTask object )
public class Network
{
private Socket handle;
public static enum TASK
{
TASK_CONNECT, TASK_SEND, TASK_CLOSE
}
public Network()
{
}
public String lastError = "";
public boolean Connect(String host, int port)
{
try
{
lastError = "Connecting to server.";
handle = new Socket(host, port);
handle.setTcpNoDelay(true); //
handle.setSendBufferSize(SIZE_OF_PACKET); ///==> These don't seem to help at all
handle.setKeepAlive(true); ///
return true;
}catch(IOException e)
{
lastError += e.getMessage() != null ? " "+ e.getMessage() : "";
return false;
}
}
private void err(String e){
System.err.println(e);
}
private boolean SendPacket(byte buffer[])
{
OutputStream oStream = null;
err("sending: " + buffer.length + " bytes");
try
{
lastError = "Obtaining output stream.";
oStream = handle.getOutputStream();
lastError = "Error sending data.";
oStream.write(buffer);
oStream.flush();
return true;
}catch(Exception e)
{
lastError += e.getMessage() != null ? " "+ e.getMessage() : "";
}
return false;
}
public void Close()
{
try{ handle.close(); handle = null; }catch(Exception e){} // swallow exception
}
}
I send my data in a loop depending on how many numbers I have. I tried a Google search but didn't find anything relevant. Has anyone experienced this before? It's making me mad now.
EDIT: Wireshark shows incoming "red" packets that don't reach the desktop app (server)
Look at this picture.
You can see the first few have Len > 0 the red ones have 0.
I think it's time Google interfaced the USB so we can use it. At least that'd would have been my first option.
Should you not be calling oStream.close() after you flush the stream, given that you never use it again?
Also, you say that this is being run in an AsyncTask object. Is it possible that multiple threads could be attempting to send packets at the same time? If so, you might need some form of synchronisation around the SendPacket method.
Ok. I solved the issue by using UDP instead. Thank you all.
But I still didn't find the source of the problem.

Android TCP app hanging on inStream.readline()

This is a continuation of this question because it my orginal question was answered, but it did not solve the bug.
Question:
How do I fix the code hanging on this line inStream.readline()
My Intent:
This is in a thread that will loop through checking if there is an outMessage, if there is, it will send the message.
Next it will check it if there is anything in the in-stream, if there is, it will send it to the handler in my main activity.
Lastly, it will sleep for 1 second, then check again.
This should allow me to read/write multiple times without needing to close and open the socket.
Problem:
It is reading and writing better, but still not working properly
What is happening now:
If outMessage is initialized with a value, upon connection with the server, the socket:
writes and flushes the value (server receives & responds)
updates value of outMessage (to null or to "x" depending on how i have it hard-coded)
reads and shows the response message from the server
re-enters for the next loop
IF i set outMessage to null, it skips over that if statements correctly then hangs; otherwise, if i set outMessage to a string (lets say "x"), it goes through the whole if statement, then hangs.
The code it hangs on is either of the inStream.readline() calls (I currently have one commented out).
Additional info:
- once connected, I can type in the "send" box, submit (updates the outMessage value), then disconnect. Upon re-connecting, it will read the value and do the sequence again until it get stuck on that same line.
Changes since the referenced question:
- Made outMessage and connectionStatus both 'volatile'
- added end-of-line delimiters in neccesary places.
Code:
public void run() {
while (connectionStatus != TCP_SOCKET_STATUS_CONNECTED) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
while (connectionStatus == TCP_SOCKET_STATUS_CONNECTED) {
try {
if (outMessage != null){
OutStream.writeBytes(outMessage + "\n");
OutStream.flush();
sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , "OUT TO SERVER: " + outMessage);
outMessage = "x";
}
Thread.sleep(100);
// if (InStream.readLine().length() > 0) {
String modifiedSentence = InStream.readLine();
sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , "IN FROM SERVER: " + modifiedSentence);
// }
Thread.sleep(1000);
} catch (IOException e) {
connectionLost();
break;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The thread that makes the socket:
public void run() {
setName("AttemptConnectionThread");
connectionStatus = TCP_SOCKET_STATUS_CONNECTING;
try {
SocketAddress sockaddr = new InetSocketAddress(serverIP, port);
tempSocketClient = new Socket(); // Create an unbound socket
// This method will block no more than timeoutMs. If the timeout occurs, SocketTimeoutException is thrown.
tempSocketClient.connect(sockaddr, timeoutMs);
OutStream = new DataOutputStream(tempSocketClient.getOutputStream());
InStream = new BufferedReader(new InputStreamReader(tempSocketClient.getInputStream()));
socketClient = tempSocketClient;
socketClient.setTcpNoDelay(true);
connected();
} catch (UnknownHostException e) {
connectionFailed();
} catch (SocketTimeoutException e) {
connectionFailed();
} catch (IOException e) {
// Close the socket
try {
tempSocketClient.close();
} catch (IOException e2) {
}
connectionFailed();
return;
}
}
Server:
public static void main(String[] args) throws IOException {
String clientSentence;
String capitalizedSentence;
try {
ServerSocket welcomeSocket = new ServerSocket(8888);
SERVERIP = getLocalIpAddress();
System.out.println("Connected and waiting for client input!\n Listening on IP: " + SERVERIP +"\n\n");
Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
while(true)
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
clientSentence = inFromClient.readLine();
System.out.println("clientSentance == " + clientSentence);
String ip = connectionSocket.getInetAddress().toString().substring(1);
if(clientSentence != null)
{
System.out.println("In from client ("+ip+")("+ System.currentTimeMillis() +"): "+clientSentence);
capitalizedSentence = clientSentence.toUpperCase() + '\n';
outToClient.writeBytes(capitalizedSentence + '\n');
System.out.println("Out to client ("+ip+"): "+capitalizedSentence);
}
}
} catch (IOException e) {
//if server is already running, it will not open new port but instead re-print the open ports information
SERVERIP = getLocalIpAddress();
System.out.println("Connected and waiting for client input!\n");
System.out.println("Listening on IP: " + SERVERIP +"\n\n");
}
}
Thanks in advance!
Edits:
added the server code after updating
I tried messing around with setting the SoTimout for the socket but took that back out
Your server is specifically designed to receive exactly one line from a client and send exactly one line back. Look at the code:
while (true) {
Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient = new BufferedReader(
new InputStreamReader(connectionSocket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(
connectionSocket.getOutputStream());
clientSentence = inFromClient.readLine();
String ip = connectionSocket.getInetAddress().toString()
.substring(1);
System.out.println("In from client (" + ip + "): "
+ clientSentence);
if (clientSentence != null) {
capitalizedSentence = clientSentence.toUpperCase() + '\n';
System.out.println("Out to client (" + ip + "): "
+ capitalizedSentence);
outToClient.writeBytes(capitalizedSentence + "\n");
}
Notice that inside the loop it accepts a new connection, reads exactly one line, and then writes exactly one line. It doesn't close the connection. It doesn't sanely end the conversation. It just stops reading.
A client that worked with this server would have to connect, send exactly one line, read exactly one line back, and then the client would have to close the connection. Your client doesn't do that. Why? Because you had no idea that's what you had to do. Why? Because you had no design ... no plan.
So that's your specific issue. But please, let me urge you to take a huge step back and totally change your approach. Before you write a single line of code, please actually design and specify a protocol at the byte level. The protocol should say what data is sent, how messages are delimited, who sends when, who closes the connection, and so on.
Otherwise, it's impossible to debug your code. Looking at the server code above, is it correct? Well, who knows. Because it's unclear what it's supposed to do. When you wrote the client, you assumed the server behaved one way. Was that assumption valid? Is the server broken? Who knows, because there's no specification of what the server is supposed to do.
You need to check if there is data available:
if (InStream.available > 0) {
String modifiedSentence = InStream.readLine();
sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , "IN FROM SERVER: " + modifiedSentence);
}
But to be honest, even that is not ideal because you have no gurantee that the eond-of-line will have been received. If the server sends a few bytes but never sends the end-of-line then you will still be blocking forever. Production socket code should never rely on readLine but instead read into a buffer and check that buffer for end-of-line (or whatever criteria your protocol needs).
Didn't read closely enough, I thought InStream was an InputStream instance. InputStream has available. InputStreamReader has ready (which in turn calls InputStream.available. As long as you keep a refernce to either of these then you can see if data is available to be read.

RFCOMM connection between two Android devices?

I have two Android devices which I want to connect, using Bluetooth, and transfer data over an RFCOMM channel. I only one one device to receive data, while the other device sends it...
Using this code, I am able to connect to the other device and begin listening to an RFCOMM channel:
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] { int.class });
socket = (BluetoothSocket) m.invoke(device, 2);
socket.connect();
class BasicThread implements Runnable{
public void run() {
try {
InputStream stream = socket.getInputStream();
BufferedReader r = new BufferedReader(new InputStreamReader(stream));
while (true){
Log.d("myapp", "now listening...");
latestLine = r.readLine();
Log.d("myapp", latestLine);
}
} catch (IOException e) {
}
}
}
new Thread(new BasicThread()).run();
Using the other device, I have implemented a listening socket like this:
Method m = blue.getClass().getMethod("listenUsingRfcommOn", new Class[] { int.class });
BluetoothServerSocket socket = (BluetoothServerSocket) m.invoke(blue, 2);
BluetoothSocket sock = socket.accept();
Log.d("myapp", "Connected...\n\n\n\n\n\n\n\n");
OutputStream s = sock.getOutputStream();
final PrintWriter out = new PrintWriter(s);
They both connect on RFCOMM channel 2, and both SEE eachother, however, the second device always remains blocked at the BluetoothSocket sock = socket.accept();
Any help?
OK, I am newbie, but I can try to help. So here is my experience, I managed to connect two devices using reflection. My Android phone is receiving data using method listenUsingInsecureRfcommOn, while other devices are masters in communication and send the data over BT SPP. I had a problem with this method since it makes no visible SDP record, so I could not detect it with other devices. Because of that, I made small sniffer using Bluecove and Java SE that tries to connect to every port in given range. Here's the code:
package application.test;
import static java.lang.System.out;
import java.io.InputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;
public class RfCommClient {
public static void main(String args[]) {
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
String add = "btspp://8C71F894A36D:";
String par = ";authenticate=false;encrypt=false;master=true";
String url = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd;HH-mm-ss-SSS");
for (int i = 1; i < 15; ++i) {
try {
url = add + i + par;
out.format("Time: %s, port = %d\n", sdf.format(System.currentTimeMillis()), i);
StreamConnection conn = (StreamConnection) Connector.open(url);
PrintStream ops = new PrintStream(conn.openOutputStream());
ops.println("Hi there...");
// response
Thread.sleep(1000);
InputStream is = conn.openInputStream();
byte[] resp = new byte[5];
int r = is.read(resp);
out.println("r = " + r + ", response = " + new String(resp, "US-ASCII"));
Thread.sleep(10 * 1000);
conn.close();
} catch (Exception e) {
out.println("Exception occured, time = " + sdf.format(System.currentTimeMillis()) + ", i = " + i);
//e.printStackTrace();
}
}
}
}
What I've learned it that some ports are taken, and that some ports can not be uses (as documentation says, e.g. port 0). For example, port 2 I believe was taken, because when I send some data to it I receive 5 chars back beginning with ERR :).
While, on the other hand, my thread is still waiting?! :)
That leads us to another thing I noticed, ports (or channels) are not always mapped to desired number. For example, to me often happened that I want to send something on port 15, but on Android, thread waiting on port 9 received the data :)
So I suggest, check which port is really allocated!
You can achieve that using the code I posted.
And another thing, here is a link to channelPicker function, which selects channel when ordinary API is used, if I am not mistaken, inside some constants should represent reserved channels.
I just noticed something, my code for registering port is slightly different, here is how I do it:
Method m = cba.getDeclaredMethod("listenUsingInsecureRfcommOn", int.class);
ss = (BluetoothServerSocket) m.invoke(BluetoothAdapter.getDefaultAdapter(), port);
Anyway, I know that this is probably too late, but, maybe someone in future has similar question.

Categories

Resources