Bind Socket Android - android

I have a problem on android. I have an application that asks the user for the local Ip address (from the device's interface) and another remote address. The application has to bind to the specified local address and connect to the remote address. Quite simple, but, indeed, bind does not work ass i expected..
I added the following permissions on the manifest file:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
The source code is the following one:
public class MainActivity extends Activity
{
String Tag = "TAG";
private int LOCAL_PORT = 4444;
private int REMOTE_PORT = 80;
private EditText LOCAL;
private EditText REMOTE;
private Button Connect;
private TextView STATUS;
private Context context = this;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LOCAL = (EditText) findViewById(R.id.editText1);
REMOTE = (EditText) findViewById(R.id.editText2);
Connect = (Button) findViewById(R.id.button1);
Connect.setOnClickListener(new View.OnClickListener() {
public void onClick(View v)
{
BotleneckHandle WORK;
Toast.makeText(getApplicationContext(), "Proceeding to connect",
Toast.LENGTH_SHORT).show();
/*
if(LOCAL.getText().toString() == null || REMOTE.getText().toString() == null || LOCAL.getText().toString().equals(" ") || REMOTE.getText().toString().equals(" ") || LOCAL.getText().toString().equals("") || REMOTE.getText().toString().equals(""))
Toast.makeText(context, "Wrong parameters", 2000);
else
{
Toast.makeText(getApplicationContext(), "Proceeding to connect",Toast.LENGTH_SHORT).show();
}*/
WORK = new BotleneckHandle();
WORK.execute();
}
});
STATUS = (TextView) findViewById(R.id.textView1);
}
private class BotleneckHandle extends AsyncTask <Void , Void , String>
{
Socket Skt = null;
String ReturnStatemente = new String();
SocketAddress localAddr = new InetSocketAddress(LOCAL.getText().toString(), LOCAL_PORT);
protected void onPreExecute(){ }
protected String doInBackground(Void... params)
{
try
{
String s=new String();
s+= "Local="+LOCAL.getText().toString()+":"+LOCAL_PORT+" Remote="+REMOTE.getText().toString()+":"+REMOTE_PORT; //so far so good, Confirmed by debug
Toast.makeText(getApplicationContext(), s,Toast.LENGTH_SHORT).show(); //Does not show anything due the fact that i didn't published it as an assync task update..
//binding to a local address
Skt.bind(localAddr); //cannot make the bind :-/
//connecting to remote host
Skt=new Socket(REMOTE.getText().toString(), REMOTE_PORT); //if bind is comment, still does not work.. I bet
ReturnStatemente = "Connected";
}
catch (UnknownHostException e)
{
e.printStackTrace();
Toast.makeText(context, "Unknown remote host", 2000);
ReturnStatemente = "Not Connected";
}
catch (IOException e)
{
e.printStackTrace();
Toast.makeText(context, "Connection fail", 2000);
ReturnStatemente = "Not Connected";
}
finally{try {
Skt.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}}
return ReturnStatemente;
}
protected void onPostExecute(String result) { STATUS.setText(" CONECTION STATUS == " + result); }
}
}
What am i doing wrong on bind? As far as i see, and as i searched for its good.. Did i miss something?
kind regards

You're trying to call bind on a variable before you assigned anything to it. So its still null. That isn't going to work. You need to create an instance of Socket before you can call methods on it.

Related

Android sockets reconnect to server

I'm building a android app that using connection with Java server (on computer).
I have a problem- when I find that there is no connection with the server, I'm trying to reconnect to the server but it doesn't work.
Here is the Client class code:
public class Client extends AsyncTask {
private final int port = 1978;
private final String ip = "192.168.14.22";
private Socket socket;
private DataOutputStream output;
private DataInputStream input;
public Client() {
}
#Override
protected Object doInBackground(Object[] objects) {
try {
socket = new Socket(ip, port);
output = new DataOutputStream(socket.getOutputStream());
input = new DataInputStream(socket.getInputStream());
Log.d("Network c1", "Connected");
} catch (IOException e) {
socket = null;
Log.d("Network c1", "Not connected");
}
return null;
}
public boolean checkConnection() {
if (output == null)
return false;
try {
output.writeUTF("abc");
return true;
} catch (IOException e) {
return false;
}
}
#Override
protected void onProgressUpdate(Object[] values) {
}
}
And the Activity code:
public class LogInActivity extends AppCompatActivity {
Client client;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_log_in);
client = new Client();
client.execute();
//I used timer because it didn't work without it- That saied always 'not connected' message/Toast
new CountDownTimer(5, 0) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
check();
}
}.start();
}
private void check() {
boolean isProcess;
isProcess = !checkConnection();
if (isProcess) {
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.Theme_AppCompat_Dialog_Alert);
builder.setTitle(getResources().getString(R.string.app_name));
builder.setMessage("Unable connect to the library");
builder.setPositiveButton("Try Again", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
//See note 1.
check();
}
});
builder.setCancelable(false);
builder.show();
}
}
public boolean checkConnection() {
if (client.checkConnection()) {
Toast.makeText(getApplicationContext(), "Connected to the library", Toast.LENGTH_SHORT).show();
return true;
} else {
Toast.makeText(this, "Unable connect to the library", Toast.LENGTH_SHORT).show();
return false;
}
}
}
Note 1:
The problem is here.
This Dialog need to be shown until the server/Library connected.
If the server is on before the app turned on, the check() method works well and says 'Connected successful' and the Dialog doesn't show.
But if when the app started, the server was unreachable, and turned on later (And became reachable)- the check() method don't work and always shows the Dialog.
What is the problem?
By the way, I tried to restart the client AsyncTask Class, but i didn't succeed.
(I tried to do close(true) to it, and after do excute() to it again, but the cancel() method didn't worked, and was a error that said that after a AsyncTask Class excuted, it can't excute again)
Thanks.
You should not check for connectivity periodically (every couple of seconds like you do in this code).
Instead you should let the OS do this for you, it will be more reliable and more efficient in terms of battery and CPU.
Take a look at this answer

How can I connect two Android device by socket without server

I am trying to develop an android application that can exchange data on peer to peer connection with other devices without server. So please suggest how can I do this. Thank you in advance.
This is a complete code for chat by SocketProgramming without server.
In my Application, first you are a client and you search for a server. When you do not find any server, you become a server and wait for a client.
public class MainActivity extends ActionBarActivity {
private Handler handler = new Handler();
private TextView text;
private EditText input;
private Button send;
private Socket socket;
private DataOutputStream outputStream;
private BufferedReader inputStream;
private String DeviceName = "Device";
private boolean searchNetwork() {
log("Connecting");
String range = "192.168.56.";
for (int i = 1; i <= 255; i++) {
String ip = range + i;
try {
socket = new Socket();
socket.connect(new InetSocketAddress(ip, 9000), 50);
outputStream = new DataOutputStream(socket.getOutputStream());
inputStream = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
DeviceName += "1";
Log.i("Server", DeviceName);
log("Connected");
return true;
} catch (Exception e) {
}
}
return false;
}
private void runNewChatServer() {
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(9000);
log("Waiting for client...");
socket = serverSocket.accept();
DeviceName += "2";
log("a new client Connected");
} catch (IOException e) {
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text);
input = (EditText) findViewById(R.id.input);
send = (Button) findViewById(R.id.send);
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
if (!searchNetwork()) {
runNewChatServer();
}
outputStream = new DataOutputStream(
socket.getOutputStream());
inputStream = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
while (true) {
String Message = inputStream.readLine();
if (Message != null) {
log(Message);
}
}
} catch (IOException e) {
log("Error: IO Exception");
e.printStackTrace();
}
}
});
send.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
if (outputStream == null) {
return;
}
try {
String Message = input.getText().toString() + "\n";
outputStream.write(Message.getBytes());
log2(input.getText().toString());
} catch (IOException e) {
e.printStackTrace();
}
input.setText("");
}
});
thread.start();
}
private void log(final String message) {
handler.post(new Runnable() {
String DeviceName2="";
#Override
public void run() {
if (DeviceName.equals("Device1")) {
DeviceName2 = "Device2";
}else if(DeviceName.equals("Device2")) {
DeviceName2 = "Device1";
}else{
DeviceName2 = "UnknowDevice";
}
text.setText(text.getText() + "\n" + DeviceName2 + " :"
+ message);
}
});
}
private void log2(final String message) {
handler.post(new Runnable() {
#Override
public void run() {
text.setText(text.getText() + "\n" + "you" + " :"
+ message);
}
});
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.exit(0);
return true;
}
return super.onKeyDown(keyCode, event);
}
}
Your design has a big problem : ...
If there is no central server some android devices should act as client and others as server but this will not work in some situations:
When the mobile telephony provider assigns private and non-public IP
When the device is connected to a Wi-Fi network but no NAT rule is defined on the router.
In both cases the problem is that the listening port of the device that must act as server is unreachable.
Java provides ServerSocket and Socket to communicate b/w devices. One of the device you can make as server and other device you can make as client and communicate b/w 'em without introducing server hosted on some machine.
The Other and better option is Using Wi-Fi Peer-to-Peer. WifiP2pManager help you to achieve your purpose.Here is an example.
If you're looking for such P2P over a local network, there are two parts to it:
Discovering peers
Communicating with peers
Among Android APIs, you can either use Network Service Discovery APIs for this or Wifi P2P Service Discovery APIs.
There's a wrapper library which which uses these internally and has comparatively better documentation - Salut, which can also be used.
I also created a library for P2P - Near, which uses sockets directly. The problem I was facing with Android APIs was that discovery wasn't happening with certainty every time and the underlying issue was unknown.
If you're looking for P2P across the internet, socket IO is a prevalent solution. Even Near should be able to facilitate the transfers if you provide the IP addresses and they're not behind NAT firewalls.

using AsyncTask for socket

I have this android code:
private class myTask extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
try {
client = new Socket("192.168.1.2", 4444);
oos = new ObjectOutputStream(client.getOutputStream());
ois = new ObjectInputStream(client.getInputStream());
oos.writeUTF("LOGIN");
oos.flush();
String emailText = email.getText().toString();
oos.writeUTF(emailText);
oos.flush();
String passwordText = password.getText().toString();
oos.writeUTF(passwordText);
oos.flush();
string = ois.readUTF();
}catch (ConnectException e){
return "Host not found";
}catch (IOException e) {
return "Exception Caught";
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if ("Host not found".equalsIgnoreCase(result)){
Toast.makeText(getApplicationContext(), "Host not found" ,Toast.LENGTH_LONG).show();
}else if("Exception Caught".equalsIgnoreCase(result)){
Toast.makeText(getApplicationContext(), "Connection error" ,Toast.LENGTH_LONG).show();
}else{
Toast.makeText(getApplicationContext(), "Connection established" ,Toast.LENGTH_LONG).show();
}
Toast.makeText(getApplicationContext(), string ,Toast.LENGTH_LONG).show();
if(string.equals("Login successfully Done!")){
startActivity(new Intent(Login.this, User.class));
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
register = (TextView)findViewById(R.id.register);
login = (Button)findViewById(R.id.login);
email = (EditText)findViewById(R.id.email);
password = (EditText)findViewById(R.id.password);
connection = (TextView)findViewById(R.id.connection);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
register.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View arg0) {
startActivity(new Intent(Login.this, Register.class));
}
});
login.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new myTask().execute();
}
});
}
but my connection create everytime i click on login button. I want my app connect to server at start and then when i press login button it sends request to server..How i need to change my code?
thanks
I think the easiest way to do that would be to move away from AsyncTasks and move to Threads. Create a new Thread in your onCreate function that creates the socket and connects it, then have it wait for a notification from the UI thread (easiest way to do this is to wait on a semaphore or message queue). Then have the onClick of the button notify the socket thread that it needs to login. With this design, you'll have it connect at startup but not login until you request it.
Your biggest worry here is if your server times out your connection for inactivity. But I assume you have control of the server to prevent that.
The problem here is that you're creating the socket in your doInBackground() method. This means that every time you execute an instance of AsyncTask that socket will be recreated. What you probably want to do is subclass Application or some sort of singleton and initialize your socket in there. Then make your AsyncTask do something like:
doInBackground(Object... params) {
// do stuff
Socket socket = Application.getSocket();
// do stuff with the socket
}
This introduces a bit of complexity as you need to handle properly opening/closing your socket at the proper points in your application lifecycle, but it is the cleanest solution that comes to mind.

AsyncTask.get() no progress bar

My app sends data to the server. It generally works fine until the user is in a bad signal area. If the user is in a good signal area the the following code works fine and the data is sent.
String[] params = new String[]{compID, tagId, tagClientId, carerID,
formattedTagScanTime, formattedNowTime, statusForWbService, getDeviceName(), tagLatitude, tagLongitude};
AsyncPostData apd = new AsyncPostData();
apd.execute(params);
.
private class AsyncPostData extends AsyncTask<String, Void, String> {
ProgressDialog progressDialog;
String dateTimeScanned;
#Override
protected void onPreExecute()
{
// progressDialog= ProgressDialog.show(NfcscannerActivity.this,
// "Connecting to Server"," Posting data...", true);
int buildVersionSdk = Build.VERSION.SDK_INT;
int buildVersionCodes = Build.VERSION_CODES.GINGERBREAD;
Log.e(TAG, "buildVersionSdk = " + buildVersionSdk
+ "buildVersionCodes = " + buildVersionCodes);
int themeVersion;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD) {
themeVersion = 2;
}else{
themeVersion = 1;
}
progressDialog = new ProgressDialog(NfcscannerActivity.this, themeVersion);
progressDialog.setTitle("Connecting to Server");
progressDialog.setMessage(" Sending data to server...");
progressDialog.setIndeterminate(true);
try{
progressDialog.show();
}catch(Exception e){
//ignore
}
};
#Override
protected String doInBackground(String... params) {
Log.e(TAG, "carerid in doinbackground = " + params[3] + " dateTimeScanned in AsyncPost for the duplecate TX = " + params[4]);
dateTimeScanned = params[4];
return nfcscannerapplication.loginWebservice.postData(params[0], params[1], params[2], params[3], params[4],
params[5], params[6], params[7] + getVersionName(), params[8], params[9]);
}
#Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
try{
progressDialog.dismiss();
}catch(Exception e){
//ignore
}
if( result != null && result.trim().equalsIgnoreCase("OK") ){
Log.e(TAG, "about to update DB with servertime");
DateTime sentToServerAt = new DateTime();
nfcscannerapplication.loginValidate.updateTransactionWithServerTime(sentToServerAt,null);
nfcscannerapplication.loginValidate.insertIntoDuplicateTransactions(dateTimeScanned);
tagId = null;
tagType = null;
tagClientId = null;
//called to refresh the unsent transactions textview
onResume();
}else if(result != null && result.trim().equalsIgnoreCase("Error: TX duplicated")){
Log.e(TAG, "response from server is Duplicate Transaction ");
//NB. the following time may not correspond exactly with the time on the server
//because this TX has already been processed but the 'OK' never reached the phone,
//so we are just going to update the phone's DB with the DupTX time so the phone doesn't keep
//sending it.
DateTime sentToServerTimeWhenDupTX = new DateTime();
nfcscannerapplication.loginValidate.updateTransactionWithServerTime(sentToServerTimeWhenDupTX,null);
tagId = null;
tagType = null;
tagClientId = null;
}else{
Toast.makeText(NfcscannerActivity.this,
"No phone signal or server problem",
Toast.LENGTH_LONG).show();
}
}
}//end of AsyncPostData
.
The app in bad signal areas tends to show the progress bar for a few minutes before showing a black screen for a while rendering the app unusable.
I thought a way around this would be to do the following.
String[] params = new String[]{compID, tagId, tagClientId, carerID,
formattedTagScanTime, formattedNowTime, statusForWbService, getDeviceName(), tagLatitude, tagLongitude};
AsyncPostData apd = new AsyncPostData();
try {
apd.execute(params).get(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
This will cause the AsyncTask to cancel after 10 seconds, but as it is executing there is a black screen until the data is sent followed by the progressbar for a few millisecs.
Is there a way to show the progressbar whilst executing an AsyncTask.get()?
thanks in advance. matt.
Also are there any ideas why the black screen comes when the user is in bad signal area and therefor no response from the server. This senario seems to cause the app alot of problems where it's behavior is unusual afterwards like sending extra transactions at a later date.
[edit1]
public class SignalService extends Service{
NfcScannerApplication nfcScannerApplication;
TelephonyManager SignalManager;
PhoneStateListener signalListener;
private static final int LISTEN_NONE = 0;
private static final String TAG = SignalService.class.getSimpleName();
#Override
public void onCreate() {
super.onCreate();
// TODO Auto-generated method stub
Log.e(TAG, "SignalService created");
nfcScannerApplication = (NfcScannerApplication) getApplication();
signalListener = new PhoneStateListener() {
public void onSignalStrengthChanged(int asu) {
//Log.e("onSignalStrengthChanged: " , "Signal strength = "+ asu);
nfcScannerApplication.setSignalStrength(asu);
}
};
}
#Override
public void onDestroy() {
super.onDestroy();
// TODO Auto-generated method stub
Log.e(TAG, "SignalService destroyed");
SignalManager.listen(signalListener, LISTEN_NONE);
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
// TODO Auto-generated method stub
Log.e(TAG, "SignalService in onStart");
SignalManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
SignalManager.listen(signalListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTH);
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
You do not need a timer at all to do what you're attempting (for some reason I thought you were trying to loop the AsyncTask based on your comments above which resulted in mine.). If I understand correctly you're issue is with the loss of service. You have an AsyncTask that you start which may or may not finish depending on certain conditions. Your approach was to use get and cancle the task after a fixed time in the event that it did not finish executing before then - the assumption being if the task didn't finish within the 10 second cut off, service was lost.
A better way to approach this problem is to use a boolean flag that indcates whether network connectivity is available and then stop the task from executing if service is lost. Here is an example I took from this post (I apologize for the formatting I'm on a crappy computer with - of all things - IE8 - so I can't see what the code looks like).
public class MyTask extends AsyncTask<Void, Void, Void> {
private volatile boolean running = true;
private final ProgressDialog progressDialog;
public MyTask(Context ctx) {
progressDialog = gimmeOne(ctx);
progressDialog.setCancelable(true);
progressDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
// actually could set running = false; right here, but I'll
// stick to contract.
cancel(true);
}
});
}
#Override
protected void onPreExecute() {
progressDialog.show();
}
#Override
protected void onCancelled() {
running = false;
}
#Override
protected Void doInBackground(Void... params) {
while (running) {
// does the hard work
}
return null;
}
// ...
}
This example uses a progress dialog that allows the user to cancle the task by pressing a button. You're not going to do that but rather you're going to check for network connectivty and set the running boolean based on whether your task is connected to the internet. If connection is lost - running will bet set to false which will trip the while loop and stop the task.
As for the work after the task complete. You should NEVER use get. Either (1) put everything that needs to be done after the doInBackgroundCompletes in onPostExecute (assuming its not too much) or (2) if you need to get the data back to the starting activity use an interface. You can add an interface by either adding as an argument to your tasks constructor or using a seperate method that sets the interface up. For example
public void setInterface(OnTaskComplete listener){
this.listener = listener;
}
Where OnTaskComplete listener is declared as an instance variable in your AsyncTask. Note the approach I am describing requires using a seperate AsyncTask class. Your's is private right now which means you need to change your project a little.
UPDATE
To check connectivity I would use something like this.
public boolean isNetworkOnline() {
boolean status=false;
try{
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getNetworkInfo(0);
if (netInfo != null && netInfo.getState()==NetworkInfo.State.CONNECTED) {
status= true;
}else {
netInfo = cm.getNetworkInfo(1);
if(netInfo!=null && netInfo.getState()==NetworkInfo.State.CONNECTED)
status= true;
}
}catch(Exception e){
e.printStackTrace();
return false;
}
return status;
}
You can check to see if there is an actual network connection over which your app can connect to ther server. This method doesn't have to be public and can be part of you're AsyncTask class. Personally, I use something similar to this in a network manager class that I use to check various network statistics (one of which is can I connect to the internet).
You would check connectivity before you started executing the loop in your doInBackground method and then you could periodicly update throughout the course of that method. If netowkr is available the task will continue. If not it will stop.
Calling the AsyncTask built in cancle method is not sufficient becuase it only prevent onPostExecute from running. It does not actually stop the code from execting.

How to display test data received from server in Android

I am writing an app that involves Client -> Server -> Client communication (one way traffic). I have my data transmitted from client A to the server, simple to test, just print to console, however, I'm trying to test to see if the data has been sent on to the next client. I have tried a text view, nothing is displaying in this view however, now I don't know if that's because the data hasn't arrived or indeed because I've coded it wrong. I'm not very experienced in android.
I've attached my code below, if anyone can help I would really appreciate it.
Regards,
Gary
public class Parent extends Activity {
private Socket s;
private PrintWriter p;
String location;
double Platitude, Plongitude;
double Clatitude, Clongitude;
double distance;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.parent);
Thread rec = new Thread(new Runnable() {
public void run() {
// TODO Auto-generated method stub
try {
s = new Socket("192.168.1.2", 1980);
InputStream fromServer = s.getInputStream();
while (s.isConnected()) {
Scanner r = new Scanner(fromServer);
if(r.hasNextLine())
{
location = r.nextLine();
}
TextView myTextview = (TextView) findViewById(R.id.dist);
myTextview.setText(location);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
rec.start();
}

Categories

Resources