前言
在前面的Channel概述的分類中提到過SocketChannel主要是用來基於TCP通信的通道。這篇文章詳細介紹下SocketChannel
- SocketChannel是什么
- SocketChannel特點
- SocketChannel的使用
SocketChannel
A selectable channel for stream-oriented connecting sockets.
以上是Java docs中對於SocketChannel的描述:SocketChannel是一種面向流連接只sockets套接字的可選擇通道。從這里可以看出:
- SocketChannel是用來連接Socket套接字
- SocketChannel主要用途用來處理網絡I/O的通道
- SocketChannel是基於TCP連接傳輸
- SocketChannel實現了可選擇通道,可以被多路復用的
SocketChannel特點
SocketChannel具有以下的特征:
- 對於已經存在的socket不能創建SocketChannel
- SocketChannel中提供的open接口創建的Channel並沒有進行網絡級聯,需要使用connect接口連接到指定地址
- 未進行連接的SocketChannle執行I/O操作時,會拋出
NotYetConnectedException
- SocketChannel支持兩種I/O模式:阻塞式和非阻塞式
- SocketChannel支持異步關閉。如果SocketChannel在一個線程上read阻塞,另一個線程對該SocketChannel調用shutdownInput,則讀阻塞的線程將返回-1表示沒有讀取任何數據;如果SocketChannel在一個線程上write阻塞,另一個線程對該SocketChannel調用shutdownWrite,則寫阻塞的線程將拋出
AsynchronousCloseException
- SocketChannel支持設定參數
參數名 | 作用描述 |
---|---|
SO_SNDBUF | 套接字發送緩沖區大小 |
SO_RCVBUF | 套接字接收緩沖區大小 |
SO_KEEPALIVE | 保活連接 |
O_REUSEADDR | 復用地址 |
SO_LINGER | 有數據傳輸時延緩關閉Channel (只有在非阻塞模式下有用) |
TCP_NODELAY | 禁用Nagle算法 |
SocketChannel的使用
1.創建SocketChannel
方式1.
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("www.baidu.com", 80));
方式2.
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("www.baidu.com", 80));
直接使用有參open api或者使用無參open api,但是在無參open只是創建了一個SocketChannel對象,並沒有進行實質的tcp連接。
2.連接校驗
socketChannel.isOpen(); // 測試SocketChannel是否為open狀態
socketChannel.isConnected(); //測試SocketChannel是否已經被連接
socketChannel.isConnectionPending(); //測試SocketChannel是否正在進行連接
socketChannel.finishConnect(); //校驗正在進行套接字連接的SocketChannel是否已經完成連接
3.讀寫模式
前面提到SocketChannel支持阻塞和非阻塞兩種模式:
socketChannel.configureBlocking(false);
主要是通過以上方法設置SocketChannel的讀寫模式。false表示非阻塞,true表示阻塞。
4.讀寫
SocketChannel socketChannel = SocketChannel.open(
new InetSocketAddress("www.baidu.com", 80));
ByteBuffer byteBuffer = ByteBuffer.allocate(16);
socketChannel.read(byteBuffer);
socketChannel.close();
System.out.println("test end!");
以上為阻塞式讀,當執行到read出,線程將阻塞,控制台將無法打印test end!。
SocketChannel socketChannel = SocketChannel.open(
new InetSocketAddress("www.baidu.com", 80));
socketChannel.configureBlocking(false);
ByteBuffer byteBuffer = ByteBuffer.allocate(16);
socketChannel.read(byteBuffer);
socketChannel.close();
System.out.println("test end!");
以上為非阻塞讀,控制台將打印test end!。
讀寫都是面向緩沖區,這個讀寫方式與前文中的FileChannel一樣,這里不再贅述。
5.設置和獲取參數
socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, Boolean.TRUE)
.setOption(StandardSocketOptions.TCP_NODELAY, Boolean.TRUE);
通過setOptions方法可以設置socket套接字的相關參數。
socketChannel.getOption(StandardSocketOptions.SO_KEEPALIVE)
socketChannel.getOption(StandardSocketOptions.SO_RCVBUF)
可以通過getOption獲取相關參數的值。如默認的接收緩沖區大小是8192byte。
前面提到SocketChannel還支持多路復用,但是多路復用在后續章節中會介紹到,故此將SocketChannel注冊到通道上,多路復用的使用,在接下來文章中會介紹。