2013-02-25 86 views
1

這是我已經試過:發送串無法正常工作

服務器:

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()

更新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()'?在閱讀數據之前還要在客戶端......? – 2013-02-26 17:15:47

+0

我的理解是當你創建一個'ByteBuffer'或任何其他類型的'Buffer'時,它們都是以寫入模式開始的,所以你必須翻轉它們才能將它們置於讀取模式。否則,我不能正確理解這件事。 – Logan 2013-02-26 17:59:52

回答

3

Buffer.flip()方法將緩衝區從 模式切換到讀取模式。調用flip()設置位置回0, 設置限制到位置正好是。
位置現在標誌着讀取位置,並限制 標記多少字節,字符等進行了寫入緩存 - 在 限制的多少字節,字符等,可以是閱讀

如果您在Buffer.flip()文檔看它指出:

在通道讀取序列或put操作之後,調用此方法 以準備通道寫入或相對獲取操作序列。

並且進一步指出:

此方法與compact方法當從一個地方 將數據傳送到另一結合經常被使用。

在你的情況,put操作不用於ByteBuffer創作。所以你必須在調用flip之前調用compact方法。

compact()ByteBuffer's方法保持這種:

緩衝區當前位置和界限之間的字節,如果有的話, 被複制到緩衝器的開始。也就是說,索引 處的字節p = position()被複制到索引零,索引p + 1處的字節被複制到索引1,等等,直到索引limit()-1 處的字節被複制到index n = limit() - 1 - p。緩衝區的位置是 設置爲n + 1,其限制設置爲其容量。標記,如果定義, 將被丟棄。

將緩衝區的位置被設置爲複製,而不是 到零的字節數,以使本方法的調用可以被另一個相對put方法的調用緊接着 。 在寫入數據不完整時從緩衝區寫入數據後調用此方法。

在您的代碼在服務器端之前flip()被稱爲位置本身是0。因此要設置position以字節數寫入b你將不得不調用compact()方法b.flip()之前被調用,以便b.flip()設置limit到以前position這是字節數寫信給ByteBuffer,並設置position0

因此服務器代碼應該是這樣的:

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 2013-02-26 06:20:31

+0

@LoganDam:查看更新的代碼... – 2013-02-26 15:34:51

+0

我已更新我的問題。 – Logan 2013-02-26 16:20:27

0

您需要flip()read()和decode()之間的緩衝區。

+0

無論如何,緩衝區本身並不包含任何東西,所以即使翻轉也無濟於事。數據似乎在某個地方丟失了。 – Logan 2013-02-26 06:19:10