2012-02-22 3 views
0

Я пытаюсь прочитать неблокирующий сокет, чтобы избежать застревания в какой-то момент в моей программе. Кто-нибудь знает, почему, когда я пытаюсь читать всегда, возвращаю ноль? Это проблема с ByteBuffer? Эта проблема возникает в методе чтения с длиной всегда равна нулю.Чтение информации из неблокирующего SocketChanel

package com.viewt.eyebird.communication; 

import java.io.IOException; 
import java.net.InetSocketAddress; 
import java.nio.ByteBuffer; 
import java.nio.channels.SocketChannel; 
import java.util.LinkedList; 
import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

import com.viewt.eyebird.PhoneInformation; 
import com.viewt.eyebird.TrackingServiceData; 
import com.viewt.eyebird.commands.*; 

import android.os.Handler; 
import android.util.Log; 

final public class ServerCommunication { 

    protected final int socketTimeout; 
    protected final TrackingServiceData commandData; 
    protected final Handler handler; 
    protected final ServerCommunicationChecker clientChecker; 
    protected final LinkedList<Serialize> queue = new LinkedList<Serialize>(); 

    protected final ByteBuffer socketBuffer = ByteBuffer.allocate(1024); 
    protected final StringBuilder readBuffer = new StringBuilder(); 

    protected static final Pattern commandPattern = Pattern.compile(">[^<]+<"); 

    protected static final ServerCommand availableCommands[] = { new Panic(), 
      new ChangeServer(), new GetServer(), new Restart(), 
      new PasswordCleanup() }; 

    protected InetSocketAddress inetSocketAddress; 
    protected SocketChannel sChannel; 

    public ServerCommunication(Handler handler, String host, int port, 
      int timeAlive, int socketTimeout, 
      PhoneInformation phoneInformation, TrackingServiceData commandData) { 

     this.commandData = commandData; 
     this.handler = handler; 
     this.socketTimeout = socketTimeout; 

     try { 
      connect(host, port); 
     } catch (CommunicationException e) { 
      Log.getStackTraceString(e); 
     } 

     clientChecker = new ServerCommunicationChecker(handler, this, 
       timeAlive, new AliveResponse(phoneInformation)); 

     handler.postDelayed(clientChecker, timeAlive); 

    } 

    public void connect() throws CommunicationException { 
     try { 
      sChannel = SocketChannel.open(); 
      sChannel.configureBlocking(false); 
      sChannel.socket().setSoTimeout(socketTimeout); 
      sChannel.connect(inetSocketAddress); 
     } catch (IOException e) { 
      throw new CommunicationException(e); 
     } 
    } 

    public boolean isConnectionPending() { 
     return sChannel.isConnectionPending(); 
    } 

    public boolean finishConnection() throws CommunicationException { 
     try { 
      return sChannel.finishConnect(); 
     } catch (IOException e) { 
      throw new CommunicationException(e); 
     } 
    } 

    public void connect(String host, int port) throws CommunicationException { 
     inetSocketAddress = new InetSocketAddress(host, port); 
     connect(); 
    } 

    public void send(Serialize serialize) throws CommunicationException { 
     try { 
      sChannel.write(ByteBuffer 
        .wrap(String.valueOf(serialize).getBytes())); 
     } catch (IOException e) { 
      throw new CommunicationException(e); 
     } 
    } 

    public void sendOrQueue(Serialize serialize) { 
     try { 
      send(serialize); 
     } catch (Exception e) { 
      queue(serialize); 
     } 
    } 

    public void queue(Serialize serialize) { 
     queue.add(serialize); 
    } 

    @Override 
    protected void finalize() throws Throwable { 
     handler.removeCallbacks(clientChecker); 
     super.finalize(); 
    } 

    public void sync() throws CommunicationException { 
     int queueSize = queue.size(); 
     for (int i = 0; i < queueSize; i++) { 
      send(queue.getFirst()); 
      queue.removeFirst(); 
     } 
    } 

    public void read() throws CommunicationException { 

     int length, readed = 0; 

     try { 
      while ((length = sChannel.read(socketBuffer)) > 0) 
       for (readed = 0; readed < length; readed++) 
        readBuffer.append(socketBuffer.get()); 
     } catch (IOException e) { 
      throw new CommunicationException(e); 
     } finally { 
      socketBuffer.flip(); 
     } 

     Matcher matcher = commandPattern.matcher(readBuffer); 

     int lastCommand; 
     if ((lastCommand = readBuffer.lastIndexOf("<")) != -1) 
      readBuffer.delete(0, lastCommand); 

     while (matcher.find()) { 
      for (ServerCommand command : availableCommands) { 
       try { 
        command.command(matcher.group(), commandData); 
        break; 
       } catch (CommandBadFormatException e) { 
        continue; 
       } 
      } 
     } 

     if (length == -1) 
      throw new CommunicationException("Server closed"); 

    } 

} 

ответ

0

Вы используете неблокирующий канал, что означает, что он будет блокироваться до тех пор, пока данные не будут доступны. Он немедленно возвращается с 0 без блокировки, если данные недоступны.

+0

Я тестирую netcat. $ nc -l -p 9090, и то, что я пишу и отправляю, нажав enter, должно вернуться в качестве доступных данных, нет? –

0

Приложения всегда считываются из сетевых буферов.

Возможно, вы попытаетесь прочитать сразу после отправки некоторых данных, а затем, когда вы получите 0 байт, вы прекратите чтение. Вы даже не дали времени, чтобы сеть возвращала данные.

Вместо этого вы должны прочитать в цикле, и если вы не получите никаких данных, немного спать с Thread.sleep(time) (используйте около 100-300 мс), а затем повторите попытку.

Вы должны остановить цикл, если вы уже слишком долго ждали: подсчитайте спальные места, сбросьте, когда вы получите некоторые данные. Или остановитесь, когда все данные будут прочитаны.

+0

Я действительно даю время 300 мс, которое определяется другим классом управления, который делает это. По любопытству я проверил, правильно ли я отправлял пакет, и все в порядке. –

Смежные вопросы