Using socket connection i need to have two threads, one for reading and one for writing. I found other questions about socket connections but I don't understand how i can use the same socket in two different threads.
I have to create a socket in a different thread from the UI thread, so i need to start a thread to create the socket. Where can i start the two threads?
Sample code structure to give you an idea.
public class SocketActivity extends Activity {
Socket s;
OutputStream dout;
String ip = "127.0.0.1";
int port = 8080;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new Thread(new Runnable() {
#Override
public void run() {
try {
s = new Socket(ip, port);
new Thread(new ReaderRunnable(s));
new Thread(new WriteRunnable(s));
} catch (IOException e) {
e.printStackTrace();
//Handle error state
}
}
});
}
// You can put this class outside activity with public scope
class ReaderRunnable implements Runnable {
Socket socket;
public ReaderRunnable(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
if (socket != null && socket.isConnected()) {
try {
OutputStream out = new BufferedOutputStream(socket.getOutputStream());
//Do reader code
} catch (IOException e) {
e.printStackTrace();
}
} else {
//Handle error case
}
}
}
// You can put this class outside activity with public scope
class WriteRunnable implements Runnable {
Socket socket;
public WriteRunnable(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
if (socket != null && socket.isConnected()) {
try {
InputStream out = new BufferedInputStream(socket.getInputStream());
//Do writer code
} catch (IOException e) {
e.printStackTrace();
}
} else {
//Handle error case
}
}
}
}
Judging by your question this is client side. You don't have to use the socket itself in two different threads. For the read thread you use the InputStream of the socket, and for the write thread you use the OutputStream.
That way you don't have to create a seperate thread just for the socket. Both the read and write threads can be started from the UI thread. For creating the threads i refer you to the Android Documentation Processes and Threads.
Related
I am learning Android bluetooth programming. I copied most of this code from Google's Android developer website for learning. The idea is listening for connection on server is done in a new thread without blocking the UI thread. When connection request is received then connection is done on another thread and finally communication is done on another thread.
The problem is when I start the listening thread from UI thread, it block automatically and no UI is displayed (freezes). Here is the sample code:
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
setContentView(R.layout.activity_main);
...
badapter = BluetoothAdapter.getDefaultAdapter();
if (badapter == null) {
Toast.makeText(this, "No bluetooth device.", Toast.LENGTH_SHORT).show();
return;
}
if (!badapter.isEnabled()) {
Toast.makeText(this, "Bluetooth is disabled.", Toast.LENGTH_SHORT).show();
return;
}
pairedDevices = new HashMap<String, String>();
discoveredDevices = new HashMap<String, String>();
showDevices();
registerBroadcastReceiver();
//this thread blocks UI thread
ListenThread listen = new ListenThread();
listen.run();
}
And the listen thread:
public class ListenThread extends Thread {
MainActivity main;
CommunicateThread communicateThread;
private final BluetoothServerSocket serverSocket;
public ListenThread() {
main = MainActivity.getInstance();
BluetoothServerSocket tmp = null;
try {
tmp = main.badapter.listenUsingRfcommWithServiceRecord(main.NAME, main.MYUUID);
} catch (final IOException e) {
main.handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(main, "Error: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
serverSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
//keep listening until exception occurs or a socket is returned
while (true) {
try {
socket = serverSocket.accept();
} catch (final IOException e) {
main.handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(main, "Error: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
});
break;
}
// If a connection was accepted
if (socket != null) {
//call communication thread once connection is established
communicateThread = new CommunicateThread(socket);
communicateThread.run();
try {
serverSocket.close();
} catch (final IOException e) {
main.handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(main, "Error: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
break;
}
}
}
}
You are calling listen.run() on the main thread which makes it run on the main thread. You should call listen.start() which will spawn off a separate thread where the run() method will be executed.
The Runnable given to the handler will be executed on the main thread though as the Handler is for the main thread.
I had the same problem. What I understand is that every time you make a hardware call, in this case, the Bluetooth, you should do it in another thread. I moved the isEnabled() call to other thread and it solved the problem.
I write an Android socket demo which just post user's input to server.
I establish a socket from android client through wifi connection, and everything goes well, the server can receive the message send from android client. The problem is, then I close WIFI of phone, but the socket can write without exception.
The code of Android client:
public class MyActivity extends Activity {
private SocketHandlerThread thread;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
thread = new SocketHandlerThread("ScoketTest");
thread.start();
}
class SocketHandlerThread extends HandlerThread {
private Socket socket;
private Handler handler;
public SocketHandlerThread(String name) {
super(name);
}
public SocketHandlerThread(String name, int priority) {
super(name, priority);
}
#Override
public void run() {
try {
socket = new Socket("192.168.60.184", 1990);
} catch (IOException e) {
Log.e("SocketTest", e.getLocalizedMessage(), e);
}
super.run();
}
Handler getHandler() {
if (handler == null) {
handler = new Handler(getLooper());
}
return handler;
}
void send(final String text) {
Runnable runnable = new Runnable() {
public void run() {
Log.e("SocketTest", "Start send text: " + text);
try {
socket.getOutputStream().write((text + "\n").getBytes());
socket.getOutputStream().flush();
} catch (Exception e) {
Log.e("SocketTest", e.getLocalizedMessage(), e);
}
Log.e("SocketTest", "Text has been send:" + text);
}
};
getHandler().post(runnable);
}
#Override
protected void onLooperPrepared() {
runOnUiThread(new Runnable() {
#Override
public void run() {
findViewById(R.id.button).setEnabled(true);
}
});
}
}
public void send(View view) {
String text = ((EditText) findViewById(R.id.text)).getText().toString();
thread.send(text);
}
}
The code of Server:
public class SocketTestServer {
ServerSocket serverSocket;
SocketTestServer() throws IOException {
serverSocket = new ServerSocket(1990);
}
void start() throws IOException {
Socket clientSocket = serverSocket.accept();
clientSocket.getInputStream();
PrintWriter out = new PrintWriter(System.out, true);
BufferedReader in =
new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
out.println(inputLine);
}
}
public static void main(String[] args) throws IOException {
SocketTestServer server = new SocketTestServer();
server.start();
}
}
I try on several phones. On Galaxy Nexus(4.2.1) an exception was thrown as expected, but on some MOTO or HTC phones socket can still write without any exception, which means I may loss some messages that I thought has been received successfully.
How could I get known that the socket connection was broken on any type of phone?
Any suggestion will be appreciated.
p.s
I know the Connective Change Broadcast, but before receive the broadcast the client may have write some message through the broken socket.
Though adding receive check on application protocol can solve the message lossing problem, I prefer to guarantee reliability on transport layer which the TCP protocol promise to do.
I use Writer & IOException in my socket, it works fine. Try this:
public static void sendUTF(String str)
{
try
{
outWriter.write(str + '\n');
outWriter.flush();
}
catch (IOException e)
{
e.printStackTrace();
outServ.setText("Connection lost!");
}
}
public static Writer outWriter = new OutputStreamWriter(outputStream, "UTF-8");
This is a problem with the TCP stack (OS level) and is a problem difficult to solve.
It happens also if the server is the one which lose connection (try to restart your server after opening the socket and no client will notice)... you will suffer a "broken pipe error" next time you send a packet through the socket.
So, there are two scenarios:
1- broken pipe when client sends information.
In this scenario you should capture the IOException and retry to open the connection (you will have to define your retry policies).
2- broken pipe when the server lose connectivity
When the server lose connection the client doesn't notice so, In this scenario you should send packets to the server in a regular basis (polling technique) and try to reconnect just in case the connection is lost.
This is needed just if you receive from the server updates, if you traffic is always client-->server only the scenario 1 applies.
I am trying to show two consecutive images in an Android app, which are received through a socket (from a C program using sendfile). The sender code seems to work ok, and I am having issues with the Android code side.
Part of the code in the Android app is the following:
public class DisplayNewActivity extends Activity {
...
#Override
public void onCreate(Bundle savedInstanceState) {
....
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
Drawable d2;
d2 = (Drawable)msg.obj;
imageSock.setImageDrawable(d2); // to set the arrived image in the imageshow object
}
};
...
cThread = new Thread(new ClientThread());
rThread = new Thread(new RcvThread());
cThread.start();
}
public class ClientThread implements Runnable {
public void run() {
// thread used for socket connection.
...
rThread.start(); // once the connection has been established
...
}
}
#SuppressLint("HandlerLeak")
public class RcvThread implements Runnable {
public void run() {
while (connected) {
try {
InputStream inputStream = socket.getInputStream();
Drawable d = Drawable.createFromStream(inputStream, null);
Message msg = new Message();
msg.obj = d;
mHandler.sendMessage(msg);
} catch (Exception e) {
Log.e("SocketConnectionv02Activity", "C: ErrorRCVD", e);
}
}
}
}
}
The problem I am facing is that after the first image received by the Android app is shown correctly, then the next one received (which is correctly received) is not shown and leaves the imageview object showing a white space.
Any suggestion/idea to solve this issue?.
Thanks in advance for any help you could provide.
EDIT:
public class DisplayNewActivity extends Activity {
...
#Override
public void onCreate(Bundle savedInstanceState) {
....
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
Bitmap d2;
d2 = (Bitmap)msg.obj;
imageSock.setImageBitmap(d2); // to set the arrived image in the imageshow object
}
};
...
cThread = new Thread(new ClientThread());
rThread = new Thread(new RcvThread());
cThread.start();
}
public class ClientThread implements Runnable {
public void run() {
// thread used for socket connection.
...
rThread.start(); // once the connection has been established
...
}
}
#SuppressLint("HandlerLeak")
public class RcvThread implements Runnable {
public void run() {
while (connected) {
try {
DataInputStream in = new DataInputStream(socket.getInputStream());
Bitmap d = BitmapFactory.decodeStream(in);
Message msg = new Message();
msg.obj = d;
mHandler.sendMessage(msg);
} catch (Exception e) {
Log.e("SocketConnectionv02Activity", "C: ErrorRCVD", e);
}
}
}
}
}
It sounds like the issue you are having is in decoding the data into a proper image after receiving it.
I might recommend not using Drawable.createFromStream() and instead using BitmapFactory.decodeStream() or manually downloading the data into a byte[] first and using BitmapFactory.decodeByteArray(). Sometimes the latter is useful if the former can't sufficiently keep up with the decoder as the data is received.
The method you are currently using actually ends up calling BitmapFactory.descodeResourceStream(), which is used to read image data out of the local res/ package and not so much from a remote socket.
I'm developing an Android application.
This application will have a server to start a DatagramSocket as a server. It will wait for incoming message. When the socket get a message I will process it.
To start a UDP Server socket I'm going to use a Local Service. This service will have a worker thread where I'm going to listen to incoming messages.
This is my unfinished Local Service implementation:
public class UDPSocketBackgroundService extends Service
{
private static final String TAG = "UDPSocketBackgroundService";
private ThreadGroup myThreads = new ThreadGroup("UDPSocketServiceWorker");
private Handler mServiceHandler;
#Override
public void onCreate()
{
super.onCreate();
Log.v(TAG, "in onCreate()");
}
#Override
public IBinder onBind(Intent arg0)
{
try
{
new Thread(myThreads, new UDPServerThread("X", 8888)).start();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
And this is my also unfinished Worker Thread implementation:
public class UDPServerThread extends Thread
{
private static final int MESSAGE_SIZE = 256;
protected DatagramSocket socket = null;
protected boolean end = false;
public UDPServerThread(String serverName, int port) throws IOException
{
super(serverName);
socket = new DatagramSocket(port);
}
public void run()
{
while (!end)
{
try
{
byte[] buf = new byte[MESSAGE_SIZE];
// Wait an incoming message.
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
// TODO: Notify Service with packet received
}
catch (IOException e)
{
// TODO Mensaje de error.
e.printStackTrace();
}
}
}
}
Those classes have their own file (they are on different files).
Here:
socket.receive(packet);
//TODO: Notify Service with packet received
How can I notify service that we have received a packet? I want to send to service that packet also.
Here there is an example on how to communicate from Main thread to worker thread. But, I don't need that, I'm looking for an example on how to communicate from worker thread to service.
I've found this example, but I don't understand it very well because on that example both classes are declare it on the same file.
As you can see, I'm a newbie on Android development.
If you know a better approach, please tell me.
When you create the UDPServerThread, you could pass in a reference to the UDPSocketBackgroundService and then call a method on it (processPacket() for example) when packets are received. This processPacket() method will need to use some sort of synchronization.
Here's a small code excerpt of the related functions:
public class UDPSocketBackgroundService extends Service
{
....
#Override
public IBinder onBind(Intent arg0)
{
try
{
new Thread(myThreads, new UDPServerThread(this, "X", 8888)).start();
// Notice we're passing in a ref to this ^^^
}
...
}
public void processPacket(DatagramPacket packet)
{
// Do what you need to do here, with proper synchronization
}
}
public class UDPServerThread extends Thread
{
private static final int MESSAGE_SIZE = 256;
protected DatagramSocket socket = null;
protected boolean end = false;
protected UDPSocketBackgroundService = null;
public UDPServerThread(UDPSocketBackgroundService service, String serverName, int port) throws IOException
{
super(serverName);
this.service = service;
socket = new DatagramSocket(port);
}
...
public void run()
{
while (!end)
{
try
{
byte[] buf = new byte[MESSAGE_SIZE];
// Wait an incoming message.
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
service.processPacket(packet);
}
...
}
...
}
}
Notice that going this approach, the UDPSocketBackgroundService is now "tightly coupled" with the UDPServerThread. Once you get this working, you may consider refactoring it with a more elegant design where there is less coupling, but for now this should get you going :)
im trying to implement a tcp socket connection between an android app (as server) and a java based client running on windows. (short version below, without code)
Im using some sensor listener to implement a game movement (everybody knows this sensor based movement of racing games.
Ive implemented a service for that purpose, which is started out of the first activity. This service is implemented as follows (im just pasting the relevant code snippets, not the whole class):
public class ServerService extends Service {
ConnectionHandler conHandler;
#Override
public void onCreate() {
startListener();
}
private void startListener() {
conHandler = new ConnectionHandler(this);
conHandler.execute();
}
private void sendMessage(String s)
{
conHandler.write(s);
}
public void messageNotify(String s) {
//Log.d("receivedMessage", s);
}
}
The ConnectionHandler class:
public class ConnectionHandler extends AsyncTask<Void, Void, Void>{
public static int serverport = 11111;
ServerSocket s;
Socket c;
ConnectionListening conListening;
ConnectionWriting conWriting;
DataOutputStream dos;
DataInputStream dis;
ServerService server;
public ConnectionHandler(ServerService server)
{
this.server = server;
}
#Override
protected Void doInBackground(Void... params) {
try {
Log.i("AsyncTank", "doInBackgoung: Creating Socket");
s = new ServerSocket(serverport);
} catch (Exception e) {
Log.i("AsyncTank", "doInBackgoung: Cannot create Socket");
}
try {
//this is blocking until client connects
c = s.accept();
Log.d("ConnectionHandler", "client connected");
dis = new DataInputStream(c.getInputStream());
dos = new DataOutputStream(c.getOutputStream());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
conWriting = new ConnectionWriting(this.c, this.dos);
conWriting.execute();
conListening = new ConnectionListening(this.c, this.dis, this.server);
if(this.c != null)
{
Timer timer = new Timer();
timer.schedule(conListening, 0, 10);
}
Log.i("AsyncTank", "doInBackgoung: Socket created, Streams assigned");
return null;
}
public void write(String s)
{
conWriting.writeToStream(s);
}
public void messageNotify(String s) {
// TODO method stub
}
}
The ConnectionHandler ist implemented as AsyncTask similarly to the ConnectionWriting, so that the blocking of tcp methods doenst affect the whole communication.
The client is able to send messages to the server to. Because i dont know when this messages will arrive, im using a TimerTask which is executed every 10ms, to check if there is a new message.
ConnectionWriting looks as follows:
public class ConnectionWriting extends AsyncTask<Context, Void, Boolean>{
public DataOutputStream dos;
Socket c;
public ConnectionWriting(Socket c, DataOutputStream dos) {
this.dos = dos;
this.c = c;
}
#Override
protected Boolean doInBackground(Context... params) {
return true;
}
public void writeToStream(String s) {
try {
if (c != null){
//Log.i("AsynkTask", "writeToStream");
dos.writeBytes(s+"\n");
dos.flush();
Log.i("AsynkTask", "write: " +s);
} else {
Log.i("AsynkTask", "writeToStream : Cannot write to stream, Socket is closed");
}
} catch (Exception e) {
Log.i("AsynkTask", "writeToStream : Writing failed");
}
}
}
And the ConnectionListening class:
public class ConnectionListening extends TimerTask{
public DataInputStream dis;
Socket c;
ServerService server;
public ConnectionListening(Socket c, DataInputStream dis, ServerService server)
{
this.c = c;
this.dis = dis;
this.server = server;
}
#Override
public void run() {
String message = "";
try {
if (c != null) {
//Log.i("AsynkTask", "readFromStream : Reading message");
message = dis.readLine();
Log.i("AsynkTask", "read: " + message);
} else {
Log.i("AsynkTask", "readFromStream : Cannot Read, Socket is closed");
}
} catch (Exception e) {
Log.i("AsynkTask", "readFromStream : Writing failed");
}
if(message != null)
{
this.server.messageNotify(message);
}
}
}
I choose this complex, asynchronous way because the server is almost continuous sending data to the client and there are situations where the client has to send data back.
With the traditional way of using tcp sockets, it is not possible to realise a non blocking communication, so that means if the server is sending (writing), the read function blocks and i will never get the client message.
to keep it short:
Ive tested my approach but the server is always sending his data first and then getting the client messages. It is not asynchronous!? :-/
Maybe anybody can help me to solve this problem.
Or is there even a simpler way to implement that approach?
It is necessary that the communication is asynchronous! And the read has to be done automatically (what i tried to implement with this polling approach).
Ive read that i can use a single thread for the reading and one for the writing, but then i have a problem with using the write functionality (dont know how to call a function in a running thread) and with calling functions in my activities.
Im thankful for every help!
regards