2013-02-25 4 views
1

Это то, что я пробовал:Передача строки через java.nio каналы не работают правильно

Сервер:

import java.net.InetSocketAddress; 
import java.nio.*; 
import java.nio.channels.*; 
import java.nio.charset.*; 

public class JavaApplication12 { 
    public static void main(String[] args) throws Exception{ 
    Charset charset = Charset.forName("ISO-8859-1"); 
    ServerSocketChannel s = ServerSocketChannel.open(); 
    s.configureBlocking(true); 
    s.socket().bind(new InetSocketAddress(1024)); 
    CharBuffer c = CharBuffer.wrap("Hello from server!"); 
    System.out.println("writing " + c); 
    ByteBuffer b = charset.encode(c); 
    SocketChannel sc = s.accept(); 
    sc.configureBlocking(true); 
    b.flip(); 
    int a = sc.write(b); 
    sc.close(); 
    s.close(); 
    System.out.println("wrote " + a); 
} 
} 

Клиент:

import java.net.InetSocketAddress; 
import java.nio.*; 
import java.nio.channels.*; 
import java.nio.charset.*; 

public class JavaApplication11 { 

    public static void main(String[] args) throws Exception { 
    Charset charset = Charset.forName("ISO-8859-1"); 
    SocketChannel sc = SocketChannel.open(new InetSocketAddress("127.0.0.1", 1024)); 
    sc.configureBlocking(true); 
    ByteBuffer b = ByteBuffer.allocate(32); 
    b.flip(); 
    int a = sc.read(b); 
    sc.close(); 
    b.flip(); 
    CharBuffer c = charset.decode(b); 
    c.flip(); 
    System.out.println("Got " + c); 
    System.out.println("read " + a); 
} 
} 

С другой стороны, кажется, просто получить очень длинная и пустая строка, и я не могу понять, что я делаю неправильно.

Обновление: Я обновил свой код и обнаружил, что сервер записывает 0 байт. Есть байты для записи, так почему же не sc.write() ничего писать?

Update 2: С помощью Вишал в конце концов, мы имеем рабочий раствор:

Сервер:

Charset charset = Charset.forName("ISO-8859-1"); 
ServerSocketChannel s = ServerSocketChannel.open(); 
s.configureBlocking(true); 
s.socket().bind(new InetSocketAddress(1024)); 
CharBuffer c = CharBuffer.wrap("Hello from server!"); 
ByteBuffer b = charset.encode(c); 
SocketChannel sc = s.accept(); 
sc.configureBlocking(true); 
b.compact(); 
b.flip(); 
int a = sc.write(b); 
sc.close(); 
s.close(); 
System.out.println("wrote " + a); 

Клиент:

Charset charset = Charset.forName("ISO-8859-1"); 
SocketChannel sc = SocketChannel.open(new InetSocketAddress("127.0.0.1", 1024)); 
sc.configureBlocking(true); 
ByteBuffer b = ByteBuffer.allocate(32); 
int a = sc.read(b); 
sc.close(); 
b.flip(); 
CharBuffer c = charset.decode(b); 
System.out.println("Got " + c); 
+0

Почему вы используете 'b.flip()' на стороне сервера перед отправкой данных клиенту? А также на стороне клиента перед чтением данных ...? –

+0

Мое понимание заключается в том, что вы создаете 'ByteBuffer' или любой другой тип' Buffer', которые они запускают в режиме записи, поэтому вам нужно перевернуть их, чтобы поместить их в режим чтения. В противном случае я не понимаю все это правильно. – Logan

ответ

3

Buffer.flip() метод переключает буфер от записи режим в режим чтения. Вызов flip() ставит перед Поместите обратно в 0, и устанавливает предел туда, где положение просто было.
т.е. позиции Теперь отмечает позицию чтения и предел знаков, сколько байтов, символы и т.д. были написаны в буфер - предел, сколько байтов, символы и т.д., которые могут быть прочитать

Если вы видите в документации Buffer.flip() говорится, что:

После последовательности считывания канала или put операции, вызывается этот метод для подготовки к последовательности операций записи по каналу или относительной операции get.

И далее будет сказано, что:

Этот метод часто используется в сочетании с методом compact когда передача данных из одного места в другое.

В вашем случае, put операция не используется для ByteBuffer создания. Таким образом, вы должны вызвать метод compact перед вызовом флип.

ByteBuffer'scompact() метод остается, что:

байты между текущей позиции буфера и его предел, если таковые имеются, копируются в начало буфера. То есть, байт с индексом p = position() копируется в нулевой индекс, байт с индексом p + 1 равен , скопированному в индекс один и так далее, пока байт при ограничении индекса() - 1 не будет скопирован в index n = limit() - 1 - p. Затем позиция буфера установлена ​​на n + 1, а ее предел установлен на ее емкость. Знак, если он определен, отбрасывается.

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

В коде на стороне сервера Перед flip() называется позиция была сама 0. Таким образом, чтобы установить position номер байт записывается в b Вы бы назвать compact() метод до b.flip() называется так, что b.flip() устанавливает limit к предыдущему position, который число байтов писал ByteBuffer и установить position в 0.

Следовательно Ваш код сервера должен быть таким:

import java.net.InetSocketAddress; 
import java.nio.*; 
import java.nio.channels.*; 
import java.nio.charset.*; 

public class JavaApplication12 { 
    public static void main(String[] args) throws Exception{ 
    Charset charset = Charset.forName("ISO-8859-1"); 
    ServerSocketChannel s = ServerSocketChannel.open(); 
    s.configureBlocking(true); 
    s.socket().bind(new InetSocketAddress(1024)); 

    CharBuffer c = CharBuffer.wrap("Hello from server!"); 
    System.out.println("writing " + c); 
    ByteBuffer b = charset.encode(c); 
    System.out.println(new String(b.array())); 
    SocketChannel sc = s.accept(); 
    //sc.configureBlocking(true); 
    b.compact(); 
    System.out.println(b.capacity() + " "+ b.position() + " " + b.limit()); 
    b.flip(); 
    System.out.println(b.capacity() + " "+ b.position() + " " + b.limit()); 
    int a = 0; 
    while (b.hasRemaining()) 
    { 
     a += sc.write(b); 
    } 

    sc.close(); 
    s.close(); 
    System.out.println("wrote " + a); 
    } 
} 

Кроме того, на клиентской стороне код должен быть таким:

import java.net.InetSocketAddress; 
import java.nio.*; 
import java.nio.channels.*; 
import java.nio.charset.*; 

public class JavaApplication11 { 
    public static void main(String[] args) throws Exception { 
    Charset charset = Charset.forName("ISO-8859-1"); 
    SocketChannel sc = SocketChannel.open(new InetSocketAddress("127.0.0.1", 1024)); 
    sc.configureBlocking(true); 
    ByteBuffer b = ByteBuffer.allocate(32); 
    //b.flip();//Don't flip the ByteBuffer here because it sets the position to 0 and limit to 0 also. Hence no read. 
    int a = sc.read(b); 
    sc.close(); 
    b.flip();//sets the Position to 0 and limit to the number of bytes to be read. 
    CharBuffer c = charset.decode(b); 
    //c.flip();//Don't flip the ChharBuffer. Because it is setting the position to zero and limit to previous position i.e zero 
    System.out.println("Got " + c); 
    System.out.println("read " + a); 
    } 
} 

Примечание: Я поставил комментарий на где вы допустили ошибки.

+0

Не печатает ли это таким образом, давайте мне коды ASCII вместо собственно букв? Спасибо за этот бит сокета, я обязательно попробую, когда вернусь с работы. – Logan

+0

@LoganDam: см. Обновленный код ... –

+0

Я обновил свой вопрос. – Logan

0

Вам нужно перевернуть буфер буфера между read() и decode().

+0

Сам буфер не содержит ничего сразу после прочтения, так что даже переворачивание не поможет. Кажется, что данные теряются где-то на этом пути. – Logan