Reading Lines Correctly Using Telnet - java

I have an Android app, which should receive and read NMEA-sentences
e.g. $GPGLL,3751.65,S,14507.36,E*77
from a remote TCP-Server using Telnet protocol. I am using the org.apache.commons.net.telnet.TelnetClient library.
What works:
Connecting to Server
Reading some sentences without any error
Problem:
There are more than half of the sentences missing. I guess that it is a timing problem, perhaps this has also to do with the connection which gets restarted in every iteration.
Here is my MainActivity.java:
package com.example.clienttel;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import org.apache.commons.net.telnet.TelnetClient;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Go to ClientThread, where NMEA-sentences will be received
int i;
for (i = 0; i < 10000; i++) // 10000 for testing
new Thread(new ClientThread()).start();
}
class ClientThread implements Runnable {
//#Override
public void run() {
TelnetClient telnet = new TelnetClient();
// Variables
String ADDRESS = "194.66.82.11";
int PORT = 51000;
String NMEA = null;
final String TAG = "TestApp";
// Connect To Server
try {
telnet.connect(ADDRESS, PORT);
} catch (IOException e) {
e.printStackTrace();
}
// Process NMEA-sentences
InputStream inStream = telnet.getInputStream();
BufferedReader r = new BufferedReader(new InputStreamReader(inStream));
try {
NMEA = r.readLine();
} catch (IOException e) {
e.printStackTrace();
}
// Ignore "...busy" sentences
if (NMEA != null) {
if(!(NMEA.equals("*** Serial port is busy ***"))) {
Log.i(TAG, NMEA);
}
}
// Disconnect From Server
try {
telnet.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Any help would be appreciated!
EDIT:
My code now looks like this:
package com.example.clienttel;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import org.apache.commons.net.telnet.TelnetClient;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class MainActivity extends ActionBarActivity {
// Variables
public String ADDRESS = "194.66.82.11";
public int PORT = 50100;
public String NMEA = null;
public final String TAG = "TestApp";
public boolean first = true;
// Handler in mainthread
Handler handler = new Handler() {
public void handleMessage(Message msg) {
String dataString = "";
Bundle bundle = msg.getData();
Log.d("handleMessage", bundle.toString());
if (bundle.containsKey("outgoingString")) {
dataString = bundle.getString("outgoingString");
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ClientThread ct;
ct = new ClientThread();
ct.mhandler=handler;
int i;
for (i = 0; i < 10000; i++) { // 10000 for testing
// Go to ClientThread, where NMEA-sentences will be received
//new Thread(new ClientThread()).start();
ct.start();
}
}
class ClientThread implements Runnable {
public Handler mhandler = null;
#Override
public void run() {
TelnetClient telnet = new TelnetClient();
if (first) {
// Connect To Server in 1st Iteration
try {
telnet.connect(ADDRESS, PORT);
} catch (IOException e) {
e.printStackTrace();
}
first = false;
}
// Process NMEA-sentences
InputStream inStream = telnet.getInputStream();
BufferedReader r = new BufferedReader(new InputStreamReader(inStream));
try {
NMEA = r.readLine();
} catch (IOException e) {
e.printStackTrace();
}
// Handler in ClientThread to send back
Bundle b = new Bundle();
b.putString("outgoingString", NMEA);
Message m = mhandler.obtainMessage();
m.setData(b);
mhandler.sendMessage(m);
}
}
}
but I am not sure about the placement of the handlers

As #EJP said, opening an closing the connection for each line will kill the app...
A better approach is have the thread handle the communication(s) and wait for the next line, passing the data back to the main thread as a bundle message.
There are plenty of examples out there, but essentially you create a handler in your main thread:
Handler handler = new Handler()
{
public void handleMessage(Message msg)
{
String dataString = "";
Bundle bundle = msg.getData();
Log.d("handleMessage", bundle.toString());
if (bundle.containsKey("outgoingString"))
{
dataString = bundle.getString("outgoingString");
}
// you can handle other message types here....
}
and pass it (the handler) to your ClientThread (here, as mhandler) where you can send the messages back:
Bundle b = new Bundle();
b.putString("outgoingString", outgoingText);
Message m = mhandler.obtainMessage();
m.setData(b);
mhandler.sendMessage(m);

Related

Garbage value while exchanging data using socket from python to Android

Currently, I have a server(python) and client(android). I am trying to send data from an android to server to another Android using socket. The problem is data looks fine in the server, but garbage value is included when an Android get the Data from server. If I varied the size of string, then it sometimes did not receive the data and after additional sendings, the weird garbage value was received. I think it was some kind of buffer related problem, but I could not figure out the exact problem.
This is output from server : outputFromServer
This is output from android : outputFromAndroid
This is server.py. I am getting data from a client and send it to other clients.
import socket
import time
import select
host = 'myIP' # Symbolic name meaning all available interfaces
port = myPortNumber # Arbitrary non-privileged port
server_sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#socket.SOCK_STREAM
server_sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)#assure reconnect
server_sock.bind((host, port))
server_sock.listen(5)
print(server_sock)
sockets_list = [server_sock]#socket list... multiple clients
clients = {}#socket is the key, user Data will be value
print("Waiting")
def receive_message(client_socket):
try:
data = client_socket.recv(1024)
print("receive Message : " +data.decode('utf-8'))
#return data.decode('utf-8')
return {"data" : data}
except:
return False
while True:
read_sockets, _, exception_sockets = select.select(sockets_list, [], sockets_list)#read, write ,air on
for notified_socket in read_sockets:
if notified_socket == server_sock: #someone just connected
client_socket, client_address = server_sock.accept()
print(client_socket)
print(client_address)
user = receive_message(client_socket)
if user is False:
print("USER FALSE")
continue
sockets_list.append(client_socket)
clients[client_socket] = user
print("ACCEPTED connection")
else:
message = receive_message(notified_socket)
print("IN ELSE : " + message['data'].decode('utf-8'))
if message is False :
sockets_list.remove(notified_socket)
del clients[notified_socket]
continue
user = clients[notified_socket]
#share this message with everyBody
for client_socket in clients:
print("for loop")
if client_socket != notified_socket:
message_to_send = message['data']
client_socket.send(len(message_to_send).to_bytes(2, byteorder='big'))
client_socket.send(message_to_send)
for notified_socket in exception_sockets:
sockets_list.remove(notified_socket)
del clients[notified_socket]
Here is my Android(java) code for client
package com.example.testing;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
public class ConnectTcp {
private String TAG = "tcp";
private DataOutputStream dos;
private DataInputStream dis;
private Socket socket;
private Thread socketThread;
public ConnectTcp() {
}//connectTcp
void sendMessage(final String message){
socketThread = new Thread() {
public void run(){
try {
if (Thread.interrupted()) { throw new InterruptedException();}
while(!Thread.currentThread().isInterrupted()) {
// ...
try {
socket = new Socket(remoteIP, port);
Log.e(TAG, "success");
}catch (IOException ioe) {
Log.e(TAG,"ERROR");
try {
dos = new DataOutputStream(socket.getOutputStream()); // output
dis = new DataInputStream(socket.getInputStream()); // inpu
dos.writeUTF("CONNECT TO SERVER : "+ message);
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
try {
while (true) {
line = (String) dis.readUTF();
Log.w("------서버에서 받아온 값", "" + line);
}
} catch (Exception e) {
}
}
}
} catch (InterruptedException consumed){
/* Allow thread to exit */
}
}//run
};//Thread
socketThread.start();
}
void sendAdditionalMessage(final String data) throws IOException {
Thread sendMessageThread = new Thread() {
#Override
public void run() {
super.run();
try {
dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(data);
} catch (IOException e) {
e.printStackTrace();
}
}
};
sendMessageThread.start();
}
void closeSocket() throws IOException {
socket.shutdownInput();
socket.shutdownOutput();
socket.close();
socketThread.interrupt();
}
}//class
This is MainActivity.java
package com.example.testing;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Handler;
import okhttp3.FormBody;
import okhttp3.RequestBody;
public class MainActivity extends AppCompatActivity {
String getData;
TextView textView;
Button bt_connect;
Button bt_disConnect;
TextView tv_hanium;
int data = 10;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt_connect = findViewById(R.id.bt_connect);
bt_disConnect = findViewById(R.id.bt_cancel);
Button bt_goToLogin = findViewById(R.id.bt_goToLogin);
final Button bt_send = findViewById(R.id.bt_send);
final ConnectTcp connectTcp = new ConnectTcp();
bt_connect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
connectTcp.sendMessage("hello world");//connect to server
}
});
bt_disConnect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
connectTcp.closeSocket();//close socket
} catch (IOException e) {
Log.d("tcp", "fail to close ");
e.printStackTrace();
}
}
});//데이터 전송 중단
bt_send.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
connectTcp.sendAdditionalMessage("150");// send data
} catch (IOException e) {
e.printStackTrace();
}
}
});
bt_goToLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent goToLogin = new Intent(MainActivity.this, LoginActivity.class);
MainActivity.this.startActivity(goToLogin);
}
});
}
}
The Java DataOutput.writeUTF method sends the length of the string it writes. If you don't want to modify the Java side, you have to modify your receive_message Python function to read the length field. Here's a start:
def receive_message(client_socket):
try:
data = client_socket.recv(2)
# TODO: ensure 2 bytes were returned
expected_length = int.from_bytes(data, byteorder="big")
data = client_socket.recv(expected_length)
if len(data) < expected_length:
# TODO: add a loop to read more data from the socket
pass
# TODO: write your own "modified utf-8" decoder - see
# https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html
print("receive Message : " + data.decode('utf-8'))
Java's DataOutput and DataInput are not really designed for general input/output, and they make integrating with other programming languages difficult as you've discovered. If I were you I would consider migrating to a different protocol, for example one that is based on reading and writing lines of text.

Android Socket is showing "Connected" when a Client Request connection but "cant send messages"

So,It's like the title Say's i have created a Simple android Socket server and Client which Connects over Wifi. Both devices are on the same Wifi Network. The Server Shows the IP Address on which it host the connection....And in the client You have to write the IP Address on which Server is hosted.....
So, My problem is when i am Entering The IP Address in the Client The Server shows "Connected". But when i start to send messages it doesn't send the message to other side neither Server to Client nor Client to server.
//#Server Java File
package inc.teckzy.wif_chat;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.format.Formatter;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Helper extends AppCompatActivity {
EditText smessage;
TextView chat,display_status;
String str,msg="";
int serverport = 6666;
ServerSocket serverSocket;
Socket client;
Handler handler = new Handler();
WifiManager wmanager;
Boolean Alive;
DataOutputStream out;
DataInputStream in;
Button button_sent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_helper);
wmanager = (WifiManager) getSystemService(WIFI_SERVICE);
#SuppressWarnings("deprecation")
String ip = Formatter.formatIpAddress(wmanager.getConnectionInfo().getIpAddress());
smessage = (EditText) findViewById(R.id.smessage);
chat = (TextView) findViewById(R.id.chat);
display_status = (TextView) findViewById(R.id.display_status);
Thread serverThread = new Thread(new serverThread());
serverThread.start();
Alive = serverThread.isAlive();
display_status.setText("Hosted on: " + ip);
button_sent = (Button) findViewById(R.id.button_sent);
button_sent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Thread sentThread = new Thread(new sentMessage());
sentThread.start();
}
});
}
class sentMessage implements Runnable{
#Override
public void run() {
try{
client = serverSocket.accept();
out = new DataOutputStream(client.getOutputStream());
str = smessage.getText().toString();
msg = msg+"\n Server:" +str;
handler.post(new Runnable()
{
#Override
public void run()
{
chat.setText(msg);
}
});
out.writeBytes(str);
out.flush();
out.close();
client.close();
}catch(IOException e){}
}
}
public class serverThread implements Runnable {
#Override
public void run() {
try {
while (true) {
serverSocket = new ServerSocket(serverport);
client = serverSocket.accept();
handler.post(new Runnable() {
#Override
public void run() {
display_status.setText("Connected");
}
});
/*******************************************
setup i/p streams
******************************************/
in = new DataInputStream(client.getInputStream());
String line = in.readUTF();
while (!line.equals("STOP")) {
msg = msg + "\n Client : " + line;
handler.post(new Runnable() {
#Override
public void run() {
chat.setText(msg);
}
});
}
in.close();
client.close();
}
} catch (Exception e) {
}
}
}
}
//#Client Side Java File
package reciever;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.*;
import java.net.*;
import inc.teckzy.wif_chat.R;
public class ClientSide extends AppCompatActivity {
EditText serverIp,smessage;
TextView chat;
String serverIpAddress = "",msg = "",str;
Handler handler = new Handler();
Button sent,connectPhones;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client_side);
chat = (TextView) findViewById(R.id.chat);
serverIp = (EditText) findViewById(R.id.server_ip);
smessage = (EditText) findViewById(R.id.smessage);
sent = (Button) findViewById(R.id.sent_button);
connectPhones = (Button) findViewById(R.id.connect_phones);
//-----------------------Connecting to IP------------------------------//
connectPhones.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
serverIpAddress = serverIp.getText().toString();
if (!serverIpAddress.equals(""))
{
Thread clientThread = new Thread(new
ClientThread());
clientThread.start();
}
}
});
//-------------------------------Initializing sent thread----------------//
sent.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
Thread sentThread = new Thread(new sentMessage());
sentThread.start();
}
});
}
class sentMessage implements Runnable
{
#Override
public void run()
{
try
{
InetAddress serverAddr =
InetAddress.getByName(serverIpAddress);
Socket socket = new Socket(serverAddr, 6666); //
DataOutputStream os = new DataOutputStream(socket.getOutputStream());
str = smessage.getText().toString();
str = str + "\n";
msg = msg + "Client : " + str;
handler.post(new Runnable() {
#Override
public void run() {
chat.setText(msg);
}
});
os.writeUTF(str);
os.flush();
os.close();
socket.close();
}
catch(IOException e)
{
}
}
}
public class ClientThread implements Runnable
{
InetAddress serverAddr;
public void run()
{
try
{
while(true)
{
serverAddr = InetAddress.getByName(serverIpAddress);
Socket socket = new Socket(serverAddr, 6666);
/*******************************************
setup i/p streams
******************************************/
DataInputStream in = new
DataInputStream(socket.getInputStream());
String line = in.readUTF();
while (!line.equals("Stop"))
{
msg = msg + "Server : " + line + "\n";
handler.post(new Runnable()
{
#Override
public void run()
{
chat.setText(msg);
}
});
}
in.close();
socket.close();
Thread.sleep(100);
}
}
catch (Exception e)
{}
}
}
}
You are using client = serverSocket.accept(); in server side every time you need to send a message.
And in client side you are trying to create a new Socket connection using new Socket
(serverAddr, 6666); multiple times.
Maintain a single Socket connection and single data input/output stream(do not create multiple instances) and you will be good to go.
See example at:
https://github.com/nabinbhandari/android-socket-messaging
I Solved it Just deleted the "sentMessage" Thread and implemented output stream in "sent.setOnClickListener(new View.OnClickListener()" in both Activity also did some modifications..Here is the working code Activity ...Hope this will help someone
#Server Activity
package inc.teckzy.wifi_chat;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.text.format.Formatter;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class Helper extends AppCompatActivity {
EditText smessage;
TextView chat,display_status;
String str,Smsg,Cmsg="";
int serverport = 6666;
ServerSocket serverSocket;
Socket client;
Handler updateConversationHandler =new Handler();
WifiManager wmanager;
DataOutputStream out;
DataInputStream in;
Button button_sent;
StringWriter errors = new StringWriter();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_helper);
wmanager = (WifiManager) getSystemService(WIFI_SERVICE);
#SuppressWarnings("deprecation")
String ip = Formatter.formatIpAddress(wmanager.getConnectionInfo().getIpAddress());
smessage = (EditText) findViewById(R.id.smessage);
chat = (TextView) findViewById(R.id.chat);
display_status = (TextView) findViewById(R.id.display_status);
Thread serverThread = new Thread(new serverThread());
serverThread.start();
display_status.setText("Hosted on: " + ip);
button_sent = (Button) findViewById(R.id.button_sent);
button_sent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
out = new DataOutputStream(client.getOutputStream());
str = smessage.getText().toString();
Smsg = "Server:" + str;
updateConversationHandler.post(new updateUIThread(Smsg));
out.writeUTF(str);
out.flush();
}catch (Exception e) {
e.printStackTrace(new PrintWriter(errors));
updateConversationHandler.post(new updateUIThread(errors.toString()));
}
smessage.getText().clear();
}
});
}
public class serverThread implements Runnable {
#Override
public void run() {
try {
serverSocket = new ServerSocket(serverport);
while (true) {
client = serverSocket.accept();
updateConversationHandler.post(new updateUIThread("Connected"));
/*******************************************
setup i/p streams
******************************************/
in = new DataInputStream(client.getInputStream());
String line = "";
while (!line.equals("STOP")) {
line=in.readUTF();
Cmsg ="Client: "+ line;
updateConversationHandler.post(new updateUIThread(Cmsg));
}
in.close();
client.close();
}
} catch (Exception e) {
e.printStackTrace(new PrintWriter(errors));
updateConversationHandler.post(new updateUIThread(errors.toString()));
}
}
}
class updateUIThread implements Runnable {
private String msg;
updateUIThread(String str) {
this.msg = str;
}
#Override
public void run() {
chat.setText(chat.getText().toString()+ msg + "\n");
}
}
#Override
protected void onStop() {
super.onStop();
try {
// MAKE SURE YOU CLOSE THE SOCKET UPON EXITING
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
And
#Client Activity
package inc.teckzy.wifi_chat.reciever;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.text.format.Formatter;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetAddress;
import java.net.Socket;
import inc.teckzy.wifi_chat.R;
public class ClientSide extends AppCompatActivity {
EditText serverIp,smessage;
TextView chat;
String serverIpAddress = "",Smsg,Cmsg = "",str;
Handler updateConversationHandler = new Handler();
Button sent,connectPhones;
Socket socket;
DataInputStream in;
DataOutputStream out;
StringWriter errors = new StringWriter();
WifiManager wmanager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client_side);
chat = (TextView) findViewById(R.id.chat);
serverIp = (EditText) findViewById(R.id.server_ip);
wmanager = (WifiManager) getSystemService(WIFI_SERVICE);
smessage = (EditText) findViewById(R.id.smessage);
sent = (Button) findViewById(R.id.sent_button);
connectPhones = (Button) findViewById(R.id.connect_phones);
//-----------------------Connecting to IP------------------------------//
connectPhones.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
serverIpAddress = serverIp.getText().toString();
if (!serverIpAddress.equals(""))
{
Thread clientThread = new Thread(new
ClientThread());
clientThread.start();
}
}
});
//-------------------------------Initializing sent thread----------------//
sent.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
try {
out = new DataOutputStream(socket.getOutputStream());
str = smessage.getText().toString();
Cmsg = "Client: " + str;
updateConversationHandler.post(new updateUIThread(Cmsg));
out.writeUTF(str);
out.flush();
}catch(Exception e){
e.printStackTrace(new PrintWriter(errors));
updateConversationHandler.post(new updateUIThread(errors.toString()));}
smessage.getText().clear();
}
});
}
public class ClientThread implements Runnable
{
InetAddress serverAddr;
public void run()
{
try
{
serverAddr = InetAddress.getByName(serverIpAddress);
socket = new Socket(serverAddr, 6666);
updateConversationHandler.post(new updateUIThread("Connected"));
String ip = socket.getRemoteSocketAddress().toString();
updateConversationHandler.post(new updateUIThread(ip));
out = new DataOutputStream(socket.getOutputStream());
in = new DataInputStream(socket.getInputStream());
/*******************************************
setup i/p streams
******************************************/
String line = "";
while (!line.equals("Stop")) {
line=in.readUTF();
Smsg ="Server: " + line + "\n";
updateConversationHandler.post(new updateUIThread(Smsg));
}
out.close();
in.close();
socket.close();
}
catch (IOException e)
{updateConversationHandler.post(new updateUIThread("IO Error"));}
}
}
class updateUIThread implements Runnable {
private String msg;
updateUIThread(String str) {
this.msg = str;
}
#Override
public void run() {
chat.setText(chat.getText().toString()+ msg + "\n");
}
}
#Override
protected void onStop() {
super.onStop();
try {
// MAKE SURE YOU CLOSE THE SOCKET UPON EXITING
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Unable to manage multiple clients (android devices) for a single java server

I need my server to keep track of each of it's client's connection. I've been advised to use Threads. So what I'm trying to achieve is to create a Thread for each client, which should run till the client connection exists. But what is happening is that for each message any client sends, a new client connection gets created in the doInBackground() function. So instead of having one single thread for one single client, I'm getting one thread for any client message sent to the server. Can you suggest a method in with which my server would be able to distinguish different messages sent from different clients?
Java Server Code :
package com.nss.academyassistserver;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class AcademyAssistServer {
public static ServerSocket serverSocket;
public static Socket clientSocket;
static final int PORT = 4444;
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
serverSocket = new ServerSocket(PORT); // Server socket
} catch (IOException e) {
System.out.println("Could not listen on port: "+PORT+" \n");
}
System.out.println("Server started. Listening to the port "+PORT);
while (true) {
try {
clientSocket = serverSocket.accept();
System.out.println("New connection accepted."); // accept the client connection
} catch (IOException ex) {
System.out.println("Problem in message reading");
}
//new thread for a client
new EchoThread(clientSocket).start();
}
}
}
class EchoThread extends Thread {
InputStreamReader inputStreamReader;
BufferedReader bufferedReader;
String fromClient;
Socket clientSocket;
public EchoThread(Socket clientSocket) {
this.clientSocket = clientSocket;
}
public void run() {
try {
inputStreamReader = new InputStreamReader(clientSocket.getInputStream());
bufferedReader = new BufferedReader(inputStreamReader); // get the client message
} catch (IOException e) {
return;
}
while (!Thread.currentThread().isInterrupted()) {
System.out.println("I am thread " + Thread.currentThread().getId());
try {
fromClient = bufferedReader.readLine();
if ((fromClient == null) || fromClient.equalsIgnoreCase("exit")) {
System.out.println("You're welcome, bye!");
return;
} else {
System.out.println(fromClient);
Thread.currentThread().interrupt();
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client Activity Code:
package com.nss.academyassist;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
//import statements for client
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Toast;
//import statements for client
import android.os.AsyncTask;
public class MainActivity extends Activity implements OnClickListener {
EditText question;
//Client sockets
private Socket client;
private PrintWriter printwriter;
private String toTag;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
question = (EditText)findViewById(R.id.editText1);
Button query = (Button)findViewById(R.id.button2);
query.setOnClickListener(this);
}
private class SendMessage extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
try {
client = new Socket("Server IP Address", 4444);
printwriter = new PrintWriter(client.getOutputStream(), true);
printwriter.write(toTag); // write the message to output stream
printwriter.flush();
printwriter.close();
client.close(); // closing the connection
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
public void onClick(View v)
{
switch(v.getId())
{
case R.id.button2:
toTag = question.getText().toString();
// Output the result
Toast.makeText(getApplicationContext(), toTag,
Toast.LENGTH_LONG).show();
//Invoke the execute method of AsynTask, which will run the doInBackground method of SendMessage Class
SendMessage sendMessageTask = new SendMessage();
sendMessageTask.execute();
break;
}
}
}
You can use IP to tell the clients. Use
clientSocket.getInetAddress().getHostAddress()
You can also keep the client not closed in the android code. For example, you may open the Socket in onCreate and close it in onDestroy.
The cause for your problem is in your client code. Using new Socket(..) your client will create a new connection each time it sends a tag to the the server. So instead of that you could create a single connection that is reused:
public class MainActivity extends Activity implements OnClickListener {
/* .. your other variables .. */
private Socket client;
private PrintWriter printwriter;
#Override
protected void onCreate(Bundle savedInstanceState) {
/* .. no change here .. */
}
public void onStart()
{
if(this.client != null)
{
try {
client = new Socket("Server IP Address", 4444);
printwriter = new PrintWriter(client.getOutputStream(), true);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void onClose()
{
this.printwriter.close();
this.printwriter = null;
this.client.close();
this.client = null;
}
private class SendMessage extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
try {
printwriter.write(toTag); // write the message to output stream
printwriter.write("\n"); // delimiter
printwriter.flush();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
public void onClick(View v)
{
switch(v.getId())
{
case R.id.button2:
toTag = question.getText().toString();
// Output the result
Toast.makeText(getApplicationContext(), toTag,
Toast.LENGTH_LONG).show();
//Invoke the execute method of AsynTask, which will run the doInBackground method of SendMessage Class
SendMessage sendMessageTask = new SendMessage();
sendMessageTask.execute();
break;
}
}
}
In addition to that you should append some delimiter to your tag/message in order for the server to be able to distinguish the content from different messages.
Since you are using BufferedReader.readLine() which seperates lines
by any one of a line feed ('\n'), a carriage return ('\r'), or a
carriage return followed immediately by a linefeed
I added a line that appends a line feed after the tag in the example above for that purpose.

how can i send my message from android client to other android client using my socket java PC server

i have my code that sucessfuly send my client message to server.. can anyone help pls ? i'm new in socket programming. i want to establish a server that sends the message of my android client to other android client... here is my code
CLIENT ANDROID :
package com.example.websocketclient;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class Chatroom extends Activity {
public static String msgToServer = null;
TextView uname;
EditText in;
Button snd;
TextView out;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chatroom);
uname = (TextView) findViewById(R.id.textViewmynam);
in = (EditText) findViewById(R.id.editTextInput);
snd = (Button) findViewById(R.id.buttonSend);
out = (TextView) findViewById(R.id.textViewOutput);
Bundle bundle = getIntent().getExtras();
String urname = bundle.getString("myname");
uname.setText(urname);
MyClientTask clientTask = new MyClientTask();
clientTask.execute();
}
public class MyClientTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... arg0) {
connect();
return null;
}
}
public void connect() {
Socket sock;
int[] allports = {1111,1919,2020};
int portnum;
for(int i=1;i<allports.length;i++) {
try {
portnum = allports[i];
boolean socketno = Middleware.available(portnum);
String ad = "192.168.149.1";
if(socketno = true) {
sock = new Socket(ad,portnum);
while(socketno) {
sendmsg(sock);
}//while
// sock.close();
}//if
}catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void sendmsg (final Socket s) {
snd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
//boolean listening = true;
String inmsg = ""+in.getText().toString();
String response = "";
msgToServer = inmsg;
//out.append("you:"+msgToServer+"\n");
try {
DataOutputStream outToServer = new DataOutputStream(s.getOutputStream());
DataInputStream inToServer = new DataInputStream(s.getInputStream());
if(outToServer != null){
outToServer.writeBytes(msgToServer+"\n");
}
}
catch (Exception e) {
}
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.chatroom, menu);
return true;
}
}
Here is my PC Server side :
package Server;
import java.net.*;
import java.io.*;
import java.util.Scanner;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.*;
public class SocketServer extends Thread {
final static int _portNumber = 1919; //Arbitrary port number
public static void main(String[] args)
{
try {
new SocketServer().startServer();
} catch (Exception e) {
System.out.println("I/O failure: " + e.getMessage());
}
}
public void startServer() throws Exception {
ServerSocket serverSocket = null;
boolean listening = true;
try {
serverSocket = new ServerSocket(_portNumber);
} catch (IOException e) {
System.err.println("Could not listen on port: " + _portNumber);
System.exit(-1);
}
while (listening) {
System.out.println("Huwat huwat kang client..!");
handleClientRequest(serverSocket);
}
serverSocket.close();
}
private void handleClientRequest(ServerSocket serverSocket) {
try {
new Thread(new ConnectionRequestHandler(serverSocket.accept())).start();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Handles client connection requests.
*/
public class ConnectionRequestHandler implements Runnable{
private Socket _socket;
private PrintWriter _out;
private BufferedReader _in;
public ConnectionRequestHandler(Socket socket) {
_socket = socket;
}
public void run() {
String info;
int maxid;
System.out.println("Client connected to socket: " + _socket.toString());
info = _socket.toString();
//incrementing the msg_id
try {
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
_socket.getOutputStream()));
_in = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
String inputLine;
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost/finalclient","root","");
PreparedStatement st = con.prepareStatement("select *from msgs order by msg_id desc");
ResultSet r1 = st.executeQuery();
r1.first(); // or r1.next()
maxid = r1.getInt("msg_id") + 1;
while ((inputLine = _in.readLine()) != null) {
System.out.println("Message from Client: "+inputLine);
out.write(inputLine);
try {
PreparedStatement st1=con.prepareStatement("insert into msgs values(?,?,?)");
st1.setInt(1,maxid);
st1.setString(2,info);
st1.setString(3,inputLine);
int count = st1.executeUpdate ();
System.out.println (count + " rows were inserted to Database");
}
catch (Exception e) {
System.out.println("Failed to Insert from DB"+e);
}
}
}
catch (Exception e) {
System.out.println("Failed to Select from DB"+e);
}
}
}
}

My app freezes, how to implement Threads in it?

Could you help me figure out how to implement Threads to this, so it won't freeze while it waits for the answer from the server?
I've tried for 5 hours or so, i simple can't find a way to use it in a thread, and then return it to set the text with tv.setText();
package zee.rhs.dk;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class AndroidClientActivity extends Activity {
private String ip = "90.184.254.246";
private int port = 8081;
private String line;
private TextView tv;
private Button btn;
private Socket socket;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv = (TextView) findViewById(R.id.tv);
btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
BufferedReader in = null;
PrintWriter out = null;
try {
socket = new Socket(ip, port);
out = new PrintWriter(socket.getOutputStream(), true);
out.println("update");
in = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
while ((line = in.readLine()) == null) {
}
tv.setText(line);
} catch (UnknownHostException e) {
Toast.makeText(AndroidClientActivity.this,
"Can't reach ip: " + ip, Toast.LENGTH_LONG).show();
e.printStackTrace();
} catch (IOException e) {
Toast.makeText(AndroidClientActivity.this,
"Accept failed at port: " + port, Toast.LENGTH_LONG)
.show();
e.printStackTrace();
} finally {
out.close();
}
}
});
}
}
AsyncTask is what you're looking for. From the help page:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
Remember that doInBackground runs in a separate thread, and onPostExecute runs in the UI thread after doInBackground completes.
Put your code, that is responsible for request to server into a separate thread:
Thread thread = new Thread() {
#Override
public void run() {
try {
// put your socket operations here
} catch (InterruptedException e) {
// handle exception if you need
}
}
};
thread.start();

Categories