2012-02-22 2 views
0

내 프로그램의 어떤 지점에서 멈추지 않도록 비 블로킹 소켓을 읽으려고합니다. 누구든지 왜 항상 0을 읽으려고하는지 알 수 있습니까? ByteBuffer에 문제가 있습니까? 이 문제는 lenght가 항상 0 인 읽기 메소드에서 발생합니다.비 블로킹 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-300ms 사용)으로 조금 잠을 잤다가 다시 시도하십시오.

이미 너무 오래 기다린 경우 루프를 중지해야합니다. 잠자기를 계산하고 데이터가있을 때 재설정하십시오. 또는 모든 데이터를 읽을 때 중지하십시오.

+0

필자는 실제로이 작업을 수행하는 다른 관리 클래스에 의해 정의되는 300ms의 시간을 제공합니다. 호기심에 의해 나는 제대로 포장을 보내고 있는지 확인했다. –