關於NIO進行socket通訊的一個不解的地方

zhoulei984623發表於2009-03-10
伺服器端程式碼:

package nio.tcp;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Iterator;
import java.util.Set;

public class UnblockServer {
	public static void main(String[] args) {
		SocketChannel socket = null;
		try {
			// 開啟一個選擇器
			Selector selector = Selector.open();

			// 客戶端要使用SocketChannel,對應伺服器的ServerSocketChannel
			ServerSocketChannel ssc = ServerSocketChannel.open();

			// 繫結伺服器IP和埠
			InetSocketAddress isa = new InetSocketAddress(8710);
			ssc.socket().bind(isa);
			ssc.configureBlocking(false);

			// 向selector註冊,要處理的是接收傳入事件,所以許可權設定為OP_ACCEPT
			SelectionKey acceptKey = ssc.register(selector,SelectionKey.OP_ACCEPT);

			// 操作?
			while (selector.select() > 0) {
				Set<SelectionKey> readyKeys = selector.selectedKeys();
				Iterator it = readyKeys.iterator();
				while (it.hasNext()) {
					SelectionKey key = (SelectionKey) it.next();
					it.remove();
					if (key.isAcceptable()) {
						System.out.println("Key is Acceptable");
						socket = (SocketChannel) ssc.accept();
						socket.configureBlocking(false);
						socket.register(selector,
								SelectionKey.OP_READ | SelectionKey.OP_WRITE);
					}
					if (key.isReadable()) {
						System.out.println("Key is readable");
						socket = (SocketChannel) key.channel();
						ByteBuffer buf = ByteBuffer.allocate(1024);
						socket.read(buf);
						buf.flip();
						// 這段實用
						Charset charset = Charset.forName("us-ascii");
						CharsetDecoder decoder = charset.newDecoder();
						CharBuffer charBuffer = decoder.decode(buf);
						String result = charBuffer.toString();
						System.out.println("Receive Data:" + result);
					}
					if (key.isWritable()) {
						System.out.println("Key is writable");
						String msg = "Message from server";
						socket = (SocketChannel) key.channel();
						//型別轉換,實用
						Charset set = Charset.forName("us-ascii");
						CharsetDecoder dec = set.newDecoder();
						CharBuffer charBuf = dec.decode(ByteBuffer.wrap(msg.getBytes()));
						System.out.println("Message from server:" + charBuf.toString());
						int nBytes = socket.write(ByteBuffer.wrap((charBuf.toString()).getBytes()));
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
}
<p class="indent">


客戶端程式碼:


package nio.tcp;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class UnblockClient {
	
	public static void main(String[] args) {
		try {
			
			InetSocketAddress ia = new InetSocketAddress(InetAddress.getLocalHost(),8710);
			
			//客戶端要使用SocketChannel,對應伺服器的ServerSocketChannel
			SocketChannel client = SocketChannel.open();
			client.connect(ia);
			//設定為非阻塞,否則就和剛才的程式沒啥區別了
			client.configureBlocking(false);
			
			//傳送資料
			sendMessage(client);
			
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static int sendMessage(SocketChannel client) {
		System.out.println("Inside SendMessage");
		String msg = null;
		ByteBuffer bytebuf;
		int nBytes = 0;
		try {
			msg = "It's message from client!";
			System.out.println("msg is "+msg);
			bytebuf = ByteBuffer.wrap(msg.getBytes());
			for (int i = 0; i < 3; i++) {
				nBytes = client.write(bytebuf);
				System.out.println(i + " finished");
			}
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			client.close();
			return -1;

		} catch (IOException e) {
			e.printStackTrace();
		}
		return nBytes;
	 }
}
<p class="indent">


我已經和網上的N多類似程式對照過了,但是我就是弄不明白,為什麼客戶端明明只是傳送了三次資料,而伺服器端卻會不停地執行write和read操作呢?不是應該執行一次之後就完了的嗎?

相關文章