Naga: Async Sockets in Android

66 views
Skip to first unread message

Jalal

unread,
Jan 24, 2011, 6:03:09 AM1/24/11
to Naga Users
Hi,

First of all, thanks for your collaboration and the good work
(Cristopher and all the members). I'm trying to develop and Android
app that sends some files to a server via a TCP socket. It needs to be
asynchronous because I need to asynchronously attend to some socket
events e.g. onReadytoSend, onConnect, etc. If using Naga libraries, do
I need to implement threads if I don't want to block the UI? or Naga
will take care of it?. Another thing, is there a place where I could
find documentation about the Naga classes and methods?

I think that Naga could really help me, but I just don't know how to
start! Again, thanks a lot.

Cheers,
Jalal

Nuoji

unread,
Jan 24, 2011, 9:09:39 AM1/24/11
to Naga Users
Hi Jajal,

Naga only requires you to run NIOService every once in a while. This
can either be done on the UI-thread or on a separate thread.

If you do it on a separate thread, you need to keep in mind that the
callbacks run on that thread, so you might need to sync back with the
UI-thread if you are accessing things there.

The absolutely simplest way is to make sure that the UI-thread runs
"selectNonBlocking()" every once in a while. Every time the call is
run, NIOService will do as much IO as possible without blocking and
then return. Any callbacks from Naga will run directly from that call
as well.

The javadocs are here: http://www.millenniummonkey.com/hosted/nagadocs/api/index.html

If you describe more in detail the way you want to send the files, I
could probably give you some short code examples.

The EchoServer example shows how to create the NIOService with a
separate thread:
http://code.google.com/p/naga/wiki/EchoServer


/Christoffer

Jalal Souky

unread,
Jan 24, 2011, 4:26:32 PM1/24/11
to naga-...@googlegroups.com
Hi Cristoffer (Sorry for misspelling it the first time),

Thanks for the prompt response! 

I just need my Android app to open a TCP connection and send audio files, pictures, etc to a server. The "difficulty" appears when the connection is lost because I should be able to resume the transfer once the connection is reestablished. Also the user might want to stop/resume/cancel a transfer at will. All of this should be done without blocking the UI and allowing the user to navigate through the rest of the app while the transfers take place. At another level, the files are packeted using a proprietary protocol that adds some headers (timestamps, sequence numbers, etc) and allows the server to communicate with the TCP client, i.e. ACK and error messages. This is already implemented in C++ so I'll try reusing it with Android's NDK.

I was thinking of using an Android Service class to implement all the transfer processes in the background and making it independent from the user's navigation. My concern was having to implement another thread in the Service to be able to monitor the Channel for events in the Selector (yes, I was thinking on using java.nio) and then handling them in the UI thread. After taking a glimpse at the java docs you told me, I think that Naga is by far the best option. This might be a silly question, but if I just need to implement the client side, do I need to use openServerSocket? also, Naga takes care of the multi-threading and event interruptions by it self, right?

One last thing, when I added the Naga .jar files to my build path Naga's debug gave a build error, do you know if Android supports it (I'm using Eclipse)? and if not, is Naga's debugger mandatory for a proper behavior?

Sorry for the long e-mail, and thank you again for everything! It looks pretty promising, GREAT work! 

Cheers,
Jalal        

--
You received this message because you are subscribed to the Google Groups "Naga Users" group.
To post to this group, send email to naga-...@googlegroups.com.
To unsubscribe from this group, send email to naga-users+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/naga-users?hl=en.


Nuoji

unread,
Jan 24, 2011, 5:52:40 PM1/24/11
to Naga Users
Hi Jalal,

I haven't tested Naga on Android myself. If the .jar doesn't work, I'd
suggest checking out the source code. The naga source code is free to
incorporate in other projects in any way you like. You could simply
add the main source tree to your own source.

As for usage, you first instantiate a NIOService. This class wraps the
Selector and keeps track of all sockets. It does nothing but waits for
selectNonBlocking() or selectBlocking(). When either of those methods
are called, all queued IO is processed. So all Naga requires is that
either method is called regularly.
Think of it as a process queue you need to poll regularly.

If you want Naga act independently of the other threads, simply create
a thread that keeps running selectBlocking() as in the EchoServer
sample. It's just a few lines of standard code.

However, my experience is that one wants to avoid threads as much as
possible and Naga is written with that in mind. In fact, Naga could
probably comfortably sit in the UI thread if a repeating UI event (say
every 0.1s) runs a selectNonBlocking()

I'm sorry I can't be more specific, but I haven't done any Android
development.

As for openServerSocket, it corresponds to "new ServerSocket" in the
normal java libs (and openSocket to "new Socket"), so if you only run
as a client, openSocket is all you need.

For custom packets it should be straightforward to handle this.
Depending on how you delimit packets, you might need to write a custom
writer/reader. I've included a few readers/writers that work with the
ways of delimiting packets I've encountered. Let me know if you feel a
need to write a new one, because in that case it could be worth adding
an implementation to Naga.


/Christoffer
> > naga-users+...@googlegroups.com<naga-users%2Bunsubscribe@googlegrou ps.com>
> > .

Jalal Souky

unread,
Jan 25, 2011, 4:03:22 AM1/25/11
to naga-...@googlegroups.com
Hi Cristoffer,

I will start working on the implementation and I'll get back to you if I have any further questions or just to give you feedback about my Naga/Android experience. Thanks again for everything!

Cheers,
Jalal

To unsubscribe from this group, send email to naga-users+...@googlegroups.com.

Jalal Souky

unread,
Jan 31, 2011, 7:58:58 AM1/31/11
to naga-...@googlegroups.com
Hi Cristoffer,

I started to use Naga in my Android app and it works like a charm! Thanks for the great work. 

Anyhow, I'm having a problem after the connectionBroken() method gets called. Once the connection is reestablished the connectionOpened() method won't get called. As I read in the documentation, these methods "...will suspend IO on all other connections until the method returns". Inside these methods I only have Log notifications so I don't know why they are not returning (don't know if this makes sense).

Do know how can I solve this?. I'm planning on having a socket running for a long time (until user exists the app) and I need to get notified for every connect/disconnect/packet received during this time.

Thanks again.

Cheers,
Jalal

Nuoji

unread,
Jan 31, 2011, 9:51:36 AM1/31/11
to Naga Users
Hi Jalal,

I'm not sure how you mean. Once a socket sends connectionBroken, that
socket can't be used.
But I assume you are opening a new connection, not actually trying to
reuse that same socket? Do you see any errors logged to stderr?


Sincerely,

Christoffer

On Jan 31, 1:58 pm, Jalal Souky <jalalso...@gmail.com> wrote:
> Hi Cristoffer,
>
> I started to use Naga in my Android app and it works like a charm! Thanks
> for the great work.
>
> Anyhow, I'm having a problem after the connectionBroken() method gets
> called. Once the connection is reestablished the connectionOpened() method
> won't get called. As I read in the documentation, these methods "...will
> suspend IO on all other connections until the method returns". Inside these
> methods I only have Log notifications so I don't know why they are not
> returning (don't know if this makes sense).
>
> Do know how can I solve this?. I'm planning on having a socket running for a
> long time (until user exists the app) and I need to get notified for every
> connect/disconnect/packet received during this time.
>
> Thanks again.
>
> Cheers,
> Jalal
>
>
>
> On Tue, Jan 25, 2011 at 10:03 AM, Jalal Souky <jalalso...@gmail.com> wrote:
> > Hi Cristoffer,
>
> > I will start working on the implementation and I'll get back to you if I
> > have any further questions or just to give you feedback about my
> > Naga/Android experience. Thanks again for everything!
>
> > Cheers,
> > Jalal
>

Jalal Souky

unread,
Feb 1, 2011, 4:30:30 AM2/1/11
to naga-...@googlegroups.com
Hi,

Oh! I didn't know that the socket closes after a connectionBroken. In fact I was trying to use a new one, my mistake. 

One question, I can't declare NIOService as a global variable and I need to use it in another method. Let me send you some sample code if it is ok with you. 

import java.io.File;

.

.

.


public class TransferSocket extends Service{

String host = "192.168.0.20";

int port = 1740;

IOException exception;

private final IBinder mBinder = new LocalBinder();

File file = new File(Environment.getExternalStorageDirectory()+"/Tales.apk");

public class LocalBinder extends Binder{

public TransferSocket getService(){

return TransferSocket.this;

}

}

@Override

public IBinder onBind(Intent arg0) {

return mBinder;

}

@Override

  public void onCreate() {

Log.v("TransferSocket", "OnCreate()");

    }

@Override

    public int onStartCommand(Intent intent, int flags, int startId) {

        Log.v("TransferSocket", "onStartCommand()");

        

        try

        {

        //Start service

        final NIOService service = new NIOService();

        // Open socket.

            System.setProperty("java.net.preferIPv6Addresses", "false"); //just to fix emulator bug in version 2.2

            NIOSocket socket = service.openSocket(host, port);

          

        socket.listen(new SocketObserver()

            {

            public void connectionOpened(NIOSocket nioSocket)

                {

                    Log.v("SOCKET", "Connected");

                }


                public void connectionBroken(NIOSocket nioSocket, Exception exception)

                {

                Log.v("SOCKET", "Connection failed");

                }


@Override

public void packetReceived(NIOSocket arg0, byte[] arg1) 

{

Log.v("SOCKET", "Packet Received");

}

            });

            

            new Thread()

            {

            public void run()

            {

            try

            {

            while (true

            {

            service.selectNonBlocking();

            Thread.sleep(100);

            }

            }catch (Exception e){ }

            }

            }.start();

            

        }catch (Exception e){

        

        e.printStackTrace();

        }

        return START_STICKY;

    }

 

@Override

public void onDestroy() {

Log.v("TransferSocket", "onDestroy()");

this.stopSelf();

}

public void packetSend(){

byte[] buffer = new byte[1024]; //1KB

File file = new File(Environment.getExternalStorageDirectory()+"/Tales.apk");

FileInputStream input = new FileInputStream(file);

input.read(buffer);// SDCard -> buffer

socket.write(buffer);// buffer -> socket

}

}


The method packetSend() needs an instance of socket, but I can't find a way. I know this is more of a Java programming question... 

Thanks.


Cheers,

Jalal


To unsubscribe from this group, send email to naga-users+...@googlegroups.com.

Jalal Souky

unread,
Feb 1, 2011, 7:39:14 AM2/1/11
to naga-...@googlegroups.com
Hi Cristoffer,

I realized that what I was trying to do wasn't actually needed. I just send the file  inside the connectionOpened() method. I cannot think of a situation where I would need to separately start the connection and then send some file. If I have  more than one file, I can just make a class that handles queues and that's it. Sorry for the flooding and thanx for the interest.

Cheers,
Jalal

Nuoji

unread,
Feb 1, 2011, 8:25:34 AM2/1/11
to Naga Users
Hi Jalal,

Glad you found a solution. If you want to access the NIOService from
elsewhere, my spontaneous response is to wrap it in a singleton.

If you want to run NIOService in a separate thread, I recommend use
selectBlocking() instead.

The new code would be:

new Thread()
{
public void run()
{
while (true)
{
try
{
service.selectBlocking();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}.start();

A simple singleton could look a bit like this:


public class NIOServiceProvider
{
private static NIOService service = null;
public static NIOService getService()
{
if (service != null) return service;
synchronized (this)
{
try
{
service = new NIOService();
new Thread()
{
public void run()
{
while (true)
{
try
{
service.selectBlocking();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}.start();
return service;
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
}


You'd request the NIOService using NIOServiceProvider.getService().
One should always think twice before using singletons though...
Reply all
Reply to author
Forward
0 new messages