the best practise of udpchannel with selector??

Discussion in 'Java' started by lightning, Feb 18, 2008.

  1. lightning

    lightning Guest

    I wrote an module which can send and receive datagrams through UDP.
    I use a selector to manage it,but I come with a problem of 100%cpu.

    the code is as follows:

    private ConcurrentLinkedQueue<ToSendData> resps = new
    ConcurrentLinkedQueue<ToSendData>();
    ...

    while (run) {
    selector.select();//why it does not block?
    if (key.isValid() && key.isReadable()) {
    ByteBuffer buffer =
    ByteBuffer.allocate(Constant.MAX_RECEIVE_BUFFER_SIZE);
    buffer.order(ByteOrder.LITTLE_ENDIAN);
    InetSocketAddress sock = (InetSocketAddress) channel.receive(buffer);
    if (sock == null)
    continue;
    receivedDatagramCount++;
    log.info("received No." + receivedDatagramCount+ " datagram");
    String ip = sock.getAddress().getHostAddress();
    int port = sock.getPort();
    if (!Crypt.decrypt(buffer.array(), buffer.position())) {
    log.warn("УÑéʧ°Ü£¡");
    return;
    }
    buffer.flip();
    P2IHeaderInfo header = P2IHeaderInfo.getInstance(buffer);
    buffer.rewind();
    DispatchData data = new DispatchData(header, buffer, ip,port,
    receivedDatagramCount);
    Task task = new Task(Task.DISPATCH, data);
    server.sendMessage(task);
    }
    if (key.isValid() && key.isWritable()) {
    if (resps.size() > 0) {
    for (ToSendData data = resps.poll(); data != null; data =
    resps.poll()) {
    if (data.getIp().equals("e")) {
    break;
    }
    String ip = data.getIp();
    int port = data.getPort();
    ByteBuffer buffer = data.getBuffer();
    Crypt.encrypt(buffer.array(), buffer.remaining());
    byte[] x = new byte[buffer.remaining()];
    System.arraycopy(buffer.array(), 0, x, 0, buffer.remaining());
    sendDatagramCount++;
    log.info("Server sends No." + sendDatagramCount+ " datagram: ");
    channel.send(buffer,new InetSocketAddress(ip, port));
    }
    }
    // If uncomment these block,the cpu goes 100%
    // else{
    // Thread.sleep(1);
    // }
    }


    }


    It seems that udpchannel is always writable and it won't block these
    thread any bit,
    I think maybe I need another thread to send datagrams and use a
    LinkedBlockingQueue instead of ConcurrentLinkedQueue.

    What is the best practice of making this module?
     
    lightning, Feb 18, 2008
    #1
    1. Advertising

  2. lightning

    EJP Guest

    lightning wrote:
    > It seems that udpchannel is always writable

    Almost always, unless the socket send buffer is full. You shouldn't
    normally register for OP_WRITE unless you've had a short write: in the
    case of UPD, that would be a write() return of zero. If you get that,
    queue the datagram, register for OP_WRITE, and when you get OP_WRITE,
    unqueue the datagrams in the queue and try to send them all. If you
    succeed, unregister OP_WRITE again.
     
    EJP, Feb 19, 2008
    #2
    1. Advertising

  3. lightning

    lightning Guest

    Ok, I wrote the code like this:

    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.channels.DatagramChannel;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.util.Iterator;
    import java.util.concurrent.ConcurrentLinkedQueue;

    public class UDPSender implements Runnable {
    private Thread thread;

    private boolean run;

    private DatagramChannel channel;

    private Selector selector;
    private SelectionKey mykey;
    private ConcurrentLinkedQueue<String> queue = new
    ConcurrentLinkedQueue<String>();

    private String ip = "192.168.43.158";

    private int port = 2222;

    public UDPSender() {
    run = true;
    try {
    channel = DatagramChannel.open();
    channel.configureBlocking(false);
    selector = Selector.open();
    mykey=channel.register(selector, SelectionKey.OP_READ|
    SelectionKey.OP_WRITE);
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    throw new InstantiationError();
    }
    }

    public void start() {
    thread = new Thread(this);
    thread.start();
    }
    public void send(){
    queue.add("sadfasdf");
    selector.wakeup();
    }
    public void run() {
    // TODO Auto-generated method stub
    try {
    while (run) {
    if(!queue.isEmpty()){
    mykey.interestOps(SelectionKey.OP_READ|SelectionKey.OP_WRITE);
    }
    selector.select();
    Iterator<SelectionKey> iter = selector.selectedKeys()
    .iterator();
    while (iter.hasNext()) {
    SelectionKey key = iter.next();
    handle(key);
    iter.remove();
    }

    }
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    }

    private void handle(SelectionKey key) {
    if (key.isReadable()) {
    System.out.println("there are something to read");
    ByteBuffer k=ByteBuffer.allocate(1000);
    try {
    channel.receive(k);
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    System.out.println("received: --"+new String(k.array(),
    0,k.position())+"--");
    }
    if (key.isWritable()) {
    ByteBuffer x = ByteBuffer.wrap("hello".getBytes());
    Iterator<String> iter = queue.iterator();
    while (iter.hasNext()) {
    System.out.println("I send!");
    String k=iter.next();
    try {
    channel.send(x, new InetSocketAddress(ip, port));
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    queue.clear();
    key.interestOps(SelectionKey.OP_READ);
    }
    }

    public void stop() {
    run = false;
    selector.wakeup();
    }

    }



    It seems the code works well, are there any more suggestions?? thx!



    On 2ÔÂ19ÈÕ, ÏÂÎç3ʱ13·Ö, EJP <> wrote:
    > lightning wrote:
    > > It seems that udpchannel is always writable

    >
    > Almost always, unless the socket send buffer is full. You shouldn't
    > normally register for OP_WRITE unless you've had a short write: in the
    > case of UPD, that would be a write() return of zero. If you get that,
    > queue the datagram, register for OP_WRITE, and when you get OP_WRITE,
    > unqueue the datagrams in the queue and try to send them all. If you
    > succeed, unregister OP_WRITE again.
     
    lightning, Feb 20, 2008
    #3
  4. lightning

    EJP Guest

    lightning wrote:
    > Ok, I wrote the code like this:
    > mykey=channel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);

    Didn't you read what I posted at all?
    > channel.send(x, new InetSocketAddress(ip, port));

    Ditto.
    > It seems the code works well, are there any more suggestions?? thx!

    That code would still exhibit your original problem. Try what I suggested.
     
    EJP, Feb 20, 2008
    #4
  5. lightning

    lightning Guest

    Of course I got what you say and the origianl problem had already
    gone,cpu now costs nothing.
    In fact you did not see my trick here ;)

    look at the handle method:

    > queue.clear();
    > key.interestOps(SelectionKey.OP_READ);



    You see,although I registered WRITE in the beginning,but when the
    first WRITE fires,
    the handle method can unregister WRITE after doing nothing.


    So whatever I register at first does not matter and yes if I didn't
    register OP_WRITE at start it would seem more clear.

    the key is the code above in "handle" method and the following:
    > if(!queue.isEmpty()){
    > mykey.interestOps(SelectionKey.OP_READ|SelectionKey.OP_WRITE);
    > }



    On 2ÔÂ20ÈÕ, ÏÂÎç12ʱ17·Ö, EJP <> wrote:
    > lightning wrote:
    > > Ok, I wrote the code like this:
    > > mykey=channel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);

    >
    > Didn't you read what I posted at all?> channel.send(x, new InetSocketAddress(ip, port));
    > Ditto.
    > > It seems the code works well, are there any more suggestions?? thx!

    >
    > That code would still exhibit your original problem. Try what I suggested.
     
    lightning, Feb 20, 2008
    #5
  6. lightning

    EJP Guest

    So all you need to do now is implement the rest of what I said ...
     
    EJP, Feb 20, 2008
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. exquisitus
    Replies:
    0
    Views:
    494
    exquisitus
    Feb 20, 2005
  2. VisionSet
    Replies:
    0
    Views:
    852
    VisionSet
    Aug 19, 2003
  3. Rich

    Architecture best practise

    Rich, Jun 30, 2006, in forum: ASP .Net
    Replies:
    5
    Views:
    520
    Nick Malik [Microsoft]
    Jul 11, 2006
  4. Mat

    Video file - best practise

    Mat, Aug 14, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    355
    =?Utf-8?B?Y2xpY2tvbg==?=
    Aug 14, 2006
  5. GW

    Best Practise

    GW, Nov 17, 2006, in forum: ASP .Net
    Replies:
    2
    Views:
    416
Loading...

Share This Page