2013-10-06 6 views
0

Моя проблема заключается в том, как получить данные из примера сервера «разрезание» в посылки 1024 байта, потому что, когда ответ приходит от сервера в пакетах, таких как 2 части, я не знаю, как это решить. Пример. Когда первый пакет поступает, размер, сообщенный сервером, равен 1988 году, а принятое значение равно 1444, что все в порядке, но когда второй пакет поступает, информированный размер является чем-то вроде 808333347 и получил 540, сумма 1444 + 540 = 1984, которая права , Я не знаю, откуда этот номер 808333347. Я ищу Google для этого решения, и все они учатся с помощью udp, и мне это нужно для подключения tcp/ip. Пожалуйста, помогите мне, решите это.Java nio read bytebuffer из канала

Класс:

public class Connection implements Runnable { 
    private static Connection  instance; 
    private   SocketChannel channel  = null; 
    private   int   port   = 0; 
    private   int   service  = 0; 
    private final int   SOCKET_TIMEOUT = 15 * 1000; 
    private final int   SOCKET_BYTES = 16 * 1024; 
    private final Charset  CHARSET  = Charset.forName("ISO-8859-1"); 
    private   String   host   = null; 
    private   String   message  = ""; 

public Connection(String host, String port){ 
    this.host  = host; 
    this.port  = Integer.parseInt(port); 
} 
public static Connection createConnection(String host, String port) { 
    if(instance == null){ 
     instance = new Conexao(host, port); 
    } 
    return instance; 
} 
public void connect(){ 
    try{ 
     instance.channel = SocketChannel.open(); 
     instance.channel.socket().setSoTimeout(SOCKET_TIMEOUT); 
     instance.channel.socket().setTcpNoDelay(false); 
     instance.channel.socket().setKeepAlive(true); 
     instance.channel.connect(new InetSocketAddress(host, port)); 
     instance.channel.configureBlocking(false); 
    } catch (IOException ioe){ 
     Log.d(TAG, ioe.getMessage() + " " + ioe.toString()); 
    } 
} 
@Override public void run() { 
    if(null != instance.channel){ 
     if(instance.channel.isConnected()){ 
      Log.d(TAG, "CHANNEL CONNECTED = TRUE"); 
     } else { 
      Log.d(TAG, "CHANNEL CONNECTED = FALSE"); 
     } 
    } else { 
     instance.connect(); 
     Log.d(TAG, "CHANNEL CONNECTED"); 
    } 
    sendMessage(); 
    while(true){ 
     receiveMessage(); 
    } 
} 
public void sendMessage() { 
    int   size = message.length(); 
    ByteBuffer buffer = ByteBuffer.allocate(4 + 4 + size); 
    buffer.putInt(service).putInt(size).put(message.getBytes()); 
    buffer.flip(); 
    for(int i = 0; i < size; i++){ 
     try { 
      instance.channel.write(buffer); 
     } catch (IOException ioe) { 
      Log.d(TAG, ioe.getMessage() + " " + ioe.toString()); 
     } 
    } 
} 
public void receiveMessage(){ 
    ByteBuffer buffer  = ByteBuffer.allocateDirect(SOCKET_BYTES); 
    int   bytesReaded = 0; 
    String  received = ""; 
    buffer.clear(); 
    try { 
     do { 
      bytesReaded = instance.channel.read(buffer); 
     } while (bytesReaded == 0); 
    } catch (IOException ioe) { 
     Log.d(TAG, ioe.getMessage() + " " + ioe.toString()); 
    } 
    buffer.flip(); 
    int size = buffer.getInt(); 
    received += CHARSET.decode(buffer); 
    Log.d(TAG,"SERVIÇE: " + size + "/" + received.length() + " MSG: " + received); 
} 
public int getService() { 
    return service; 
} 
public void setService(int service) { 
    this.service = service; 
} 
public String getMessage() { 
    return message; 
} 
public void setMessage(String message) { 
    this.message = message; 
} 

Я изменил функцию так:

public void receiveMessage(){ 
    ByteBuffer buffer  = ByteBuffer.allocateDirect(SOCKET_BYTES); 
    int   bytesReaded = 0; 
    String  received = ""; 
    buffer.clear(); 
    try { 
     bytesReaded = instance.channel.read(buffer); 
    } catch (IOException ioe) { 
     Log.d(TAG, ioe.getMessage() + " " + ioe.toString()); 
    } 
    buffer.flip(); 
    if(bytesReaded >= 4){ 
     if(size == 0 && size < 5000) size = buffer.getInt(); 
     received += CHARSET.decode(buffer); 
     answer  += received; 
     if(size == answer.length()){ 
      Log.d(TAG,"SERVICE: " + size + "/" + answer.length() + " " + answer); 
     } 
    } 
} 

Но это очень некрасиво прямо сейчас.

ответ

0

Вы не можете контролировать, как данные поступают в TCP-соединение, с любого конца. Он может поступать в байт за раз или в любые другие кванты вплоть до размера данных. Вы должны зациклиться на принимающей стороне, пока не получите все необходимое. Вам нужно использовать один и тот же буфер чтения для размера сокета, чтобы вы могли накапливать данные для этого цикла и сохранять любые данные, которые могут принадлежать последующему сообщению.

«Размер информации» не может быть таким огромным, как вы заявляете. Это происходит только из-за ошибки. Возможно, вы выходите из синхронизации.

+0

Я понял и решил проблему накопления данных, теперь все в порядке, но вопрос о размере, первый размер, который поступает с сервера, прав, как я могу его синхронизировать? –

+0

Убедитесь, что вы точно прочитали количество байтов сообщений, указанное словом размера. В противном случае вы будете неправильно понимать следующие слова службы/размера. – EJP

0

Проблема в том, что с помощью TCP вы не можете контролировать, как данные отправляются (фрагментированы). Вы не знаете, сколько данных считывается с channel.read(...).

Вы вызываете receiveMessage() в цикле, там вы заполняете прочитанные данные в буфер.

Вы не можете быть уверены, что

int size = buffer.getInt(); 

является размер сообщения, которое вы получаете (только в первом вызове, если вы получаете по крайней мере, 4 байта.). Вы должны помнить первые 4 полученных байта, размер (поскольку вы используете getInt()), тогда вы должны channel.read(...), пока не получите размер байтов, после чего -> обработайте следующее сообщение.

Также повторите использование своего буфера. Поскольку вы используете NIO (и неблокируетесь), я также предлагаю вам использовать select(), вместо того, чтобы заняться чтением.

+0

Я положил getMessage на запуск в цикле, потому что если я не сделаю этого, я не могу получить все сообщение, но я удалил do/while из функции, и он все еще работает хорошо. Теперь проблема состоит в том, чтобы игнорировать второй размер, который я получаю с сервера. –

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