2012-02-22 135 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輸入併發送的內容應作爲可用數據返回,否? – 2012-02-22 16:52:32

0

應用程序始終從網絡緩衝區讀取。

您可能會嘗試在您發送一些數據後立即讀取,然後在您停止讀取0字節時再嘗試讀取。你甚至沒有給網絡返回數據的時間。

取而代之的是,你應該讀一個循環,如果你沒有數據,睡一點Thread.sleep(time)(使用大約100-300ms),然後重試。

如果您已經等待太久,您應該停止循環:計算睡眠時間,在您獲取某些數據時重置。或者在讀取所有數據時停止。

+0

我真的給了300ms的時間,這是由不同的管理類定義的。好奇心,我檢查了我是否正確地發送了包裹,並且很好。 – 2012-02-22 17:06:02