首頁>技術>

客戶端/伺服器端通訊程式碼:

import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.util.Iterator;public class NetworkNIOServer {	// 通道管理器	private Selector selector;	public void initServer(String host, int port) throws IOException {		// 獲得一個ServerSocket通道,相當於傳統socket中的ServerSocket		ServerSocketChannel serverChannel = ServerSocketChannel.open();		// 設定通道為非阻塞		serverChannel.configureBlocking(false);		// 將該通道對應的ServerSocket繫結到port埠,ip預設就是本機的ip		serverChannel.socket().bind(new InetSocketAddress(host, port));		// 獲得一個通道管理器		this.selector = Selector.open();		// 將通道管理器和該通道繫結,併為該通道註冊SelectionKey.OP_ACCEPT事件,		// 註冊該事件後,當該事件到達時selector.select()會返回,		// 如果該事件沒到達selector.select()會一直阻塞		serverChannel.register(selector, SelectionKey.OP_ACCEPT);	}	public void listen() throws IOException {		// 輪詢訪問selector,select方法會阻塞		@SuppressWarnings("unused")		int count = 0;		while ((count = selector.select()) > 0) {			// 獲得selector中選中的項的迭代器,選中的項為註冊的事件			Iterator<SelectionKey> ite = this.selector.selectedKeys().iterator();			while (ite.hasNext()) {				// 獲取選中的KEY				SelectionKey key = (SelectionKey) ite.next();				// 刪除已選的key,以防重複處理				ite.remove();				handler(key);			}		}	}	private void handler(SelectionKey selectionKey) throws IOException {		if (selectionKey.isAcceptable()) {			// 客戶端請求連線事件			handlerAccept(selectionKey);		} else if (selectionKey.isReadable()) {			// 獲得可讀的事件			handelerRead(selectionKey);		}	}	private void handelerRead(SelectionKey selectionKey) throws IOException {		// 伺服器可讀取訊息:得到事件發生的Socket通道(其實就是這個請求對應的通道)		SocketChannel channel = (SocketChannel) selectionKey.channel();		// 建立讀取的緩衝區		ByteBuffer buffer = ByteBuffer.allocate(1024);		int read = channel.read(buffer);		if (read <= 0) {			System.out.println("沒有讀取到資料,客戶端關閉。");			selectionKey.cancel();		} else {			byte[] data = buffer.array();			String msg = new String(data).trim();			System.out.println("服務端收到資訊:" + msg);			// 回寫資料			ByteBuffer outBuffer = ByteBuffer.wrap("好的".getBytes());			channel.write(outBuffer);		}	}	private void handlerAccept(SelectionKey selectionKey) throws IOException {		ServerSocketChannel server = (ServerSocketChannel) selectionKey.channel();		// 獲得和客戶端連線的通道		SocketChannel channel = server.accept();		// 設定成非阻塞		channel.configureBlocking(false);		System.out.println("新的客戶端連線");		// 在和客戶端連線成功之後,為了可以接收到客戶端的資訊,需要給通道設定讀的許可權。		channel.register(this.selector, SelectionKey.OP_READ);	}	public static void main(String[] args) throws IOException {		NetworkNIOServer server = new NetworkNIOServer();		server.initServer("0.0.0.0",8000);		server.listen();	}}
import java.io.IOException;import java.net.InetSocketAddress;import java.net.SocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SocketChannel;public class NetworkNIOClient {	public static void main(String[] args) {		// 獲得一個SocketChannel通道		try (SocketChannel socketChannel = SocketChannel.open()) {			// 連線服務端socket			SocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8000);			socketChannel.connect(socketAddress);			//			ByteBuffer buffer = ByteBuffer.allocate(1024);			int sendCount = 0;			// 這裡最好使用selector處理 這裡只是為了寫的簡單			while (sendCount < 1) {				// 把position移動到最前面,同時把limit調整為capacity				buffer.clear();				// 向服務端傳送訊息				buffer.put(("current time : " + System.currentTimeMillis()).getBytes());				// 當呼叫flip()方法之後,limit的值會改變成position的值,而position被置0。				buffer.flip();				socketChannel.write(buffer);				buffer.clear();				// 從服務端讀取訊息				int readLenth = socketChannel.read(buffer);				// 讀取模式				buffer.flip();				byte[] bytes = new byte[readLenth];				buffer.get(bytes);				System.out.println(new String(bytes, "UTF-8"));				buffer.clear();				sendCount++;				try {					Thread.sleep(1000);				} catch (InterruptedException e) {					e.printStackTrace();				}			}			// 客戶端主動關閉			socketChannel.close();		} catch (IOException e) {			e.printStackTrace();		}	}}
TCP通訊過程三次握手——連線

客戶端127.0.0.1:2254====>連線====>伺服器端127.0.0.1:8080

第一次,客戶端傳送, SYN=1, seq=x, ack=0

可以看到:SYN=1,seq=XXX,ack(Acknowledgment number) = 0

第二次,伺服器端傳送, SYN=1, ACK=1, seq=y, ack=x+1

可以看到:SYN=1, ACK=1, seq=y, ack=x+1

第三次,客戶端傳送, ACK=1, seq= x+1, ack=y+1

可以看到:ACK=1, seq= x+1, ack=y+1

通訊——傳送+確認

第一次,客戶端傳送資料給伺服器端

第二次,伺服器端確認接收資訊

第三次,伺服器端傳送資料給客戶端

第四次,客戶端確認接收資訊

4
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Python合集之Python集合(一)