0 Backlog是什麼?
BACKLOG用於構造服務端套接字ServerSocket對象,標識當服務器請求處理線程全滿時,用於臨時存放已完成三次握手的請求的隊列的最大長度。如果未設置或所設置的值小於1,Java將使用默認值50。
1 Tomcat 配置(8.5.34版本)
org.apache.coyote.AbstractProtocol中:org.apache.coyote.AbstractProtocol#setBacklog 和 org.apache.tomcat.util.net.AbstractEndpoint#setBacklog 已經廢棄,轉用org.apache.coyote.AbstractProtocol#setAcceptCount和org.apache.tomcat.util.net.AbstractEndpoint#setAcceptCount
參數:org.apache.tomcat.util.net.AbstractEndpoint#acceptCount
/**
* Allows the server developer to specify the acceptCount (backlog) that
* should be used for server sockets. By default, this value
* is 100.
*/
private int acceptCount = 100;
public void setAcceptCount(int acceptCount) { if (acceptCount > 0) this.acceptCount = acceptCount; }
springboot 相關的配置,實現相關的接口即可:org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer
實現該接口:配置最大Send_Q隊列長度爲200
@Override
public void customize(Connector connector) {
this.connector = connector;
Http11NioProtocol protocolHandler = (Http11NioProtocol)connector.getProtocolHandler();
protocolHandler.setAcceptCount(200);
}
2 NIO server端配置
// 最終由 min(backlog, /proc/sys/net/core/somaxconn) 決定Send_Q 大小
// 默認50 此處配置成100
serverSocket.bind(new InetSocketAddress(port),100);
public NIOServer(int port) throws IOException {
//開啓ServerSocketChannel
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//設置爲非阻塞
serverSocketChannel.configureBlocking(false);
//獲取ServerSocket
ServerSocket serverSocket = serverSocketChannel.socket();
//綁定ServerSocket提供服務的端口
// 最終由 min(backlog, /proc/sys/net/core/somaxconn) 決定Send_Q 大小
// 默認50 此處配置成100
serverSocket.bind(new InetSocketAddress(port),100);
//開啓選擇器
selector = Selector.open();
//將ServerSocketChannel註冊到選擇器上
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("NOIServer start run in port " + port);
}
3 Netty 配置
// BACKLOG用於構造服務端套接字ServerSocket對象,
// 標識當服務器請求處理線程全滿時,用於臨時存放已完成三次握手的請求的隊列的最大長度
bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
public class NettyServer {
/**
* 端口
*/
private int port;
public NettyServer(int port) {
this.port = port;
}
public void run() {
//EventLoopGroup是用來處理IO操作的多線程事件循環器
//負責接收客戶端連接線程
EventLoopGroup bossGroup = new NioEventLoopGroup();
//負責處理客戶端i/o事件、task任務、監聽任務組
EventLoopGroup workerGroup = new NioEventLoopGroup();
//啓動 NIO 服務的輔助啓動類
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup);
//配置 Channel
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.childHandler(new ServerIniterHandler());
//BACKLOG用於構造服務端套接字ServerSocket對象,
// 標識當服務器請求處理線程全滿時,用於臨時存放已完成三次握手的請求的隊列的最大長度
bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
//是否啓用心跳保活機制
bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
try {
//綁定服務端口監聽
Channel channel = bootstrap.bind(port).sync().channel();
System.out.println("server run in port " + port);
//服務器關閉監聽
/*channel.closeFuture().sync()實際是如何工作:
channel.closeFuture()不做任何操作,只是簡單的返回channel對象中的closeFuture對象,對於每個Channel對象,都會有唯一的一個CloseFuture,用來表示關閉的Future,
所有執行channel.closeFuture().sync()就是執行的CloseFuturn的sync方法,從上面的解釋可以知道,這步是會將當前線程阻塞在CloseFuture上*/
channel.closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//關閉事件流組
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
new NettyServer(8899).run();
}
}
4 其他Socket參數
4.1 ChannelOption.SO_KEEPALIVE, 是否啓用心跳保活機制。在雙方TCP套接字建立連接後(即都進入ESTABLISHED狀態)並且在兩個小時左右(參考 https://blog.csdn.net/qfzhangwei/article/details/90614253#comments)上層沒有任何數據傳輸的情況下,這套機制纔會被激活。
4.2 ChannelOption.TCP_NODELAY, 在TCP/IP協議中,無論發送多少數據,總是要在數據前面加上協議頭,同時,對方接收到數據,也需要發送ACK表示確認。爲了儘可能的利用網絡帶寬,TCP總是希望儘可能的發送足夠大的數據。這裏就涉及到一個名爲Nagle的算法,該算法的目的就是爲了儘可能發送大塊數據,避免網絡中充斥着許多小數據塊。TCP_NODELAY就是用於啓用或關於Nagle算法。如果要求高實時性,有數據發送時就馬上發送,就將該選項設置爲true關閉Nagle算法;如果要減少發送次數減少網絡交互,就設置爲false等累積一定大小後再發送。默認爲false。
5 Netty 相關
5.1 ChannelOption.SO_REUSEADDR, 允許啓動一個監聽服務器並捆綁其衆所周知端口,即使以前建立的將此端口用做他們的本地端口的連接仍存在。這通常是重啓監聽服務器時出現,若不設置此選項,則bind時將出錯。 SO_REUSEADDR允許在同一端口上啓動同一服務器的多個實例,只要每個實例捆綁一個不同的本地IP地址即可。對於TCP,我們根本不可能啓動捆綁相同IP地址和相同端口號的多個服務器。 SO_REUSEADDR允許單個進程捆綁同一端口到多個套接口上,只要每個捆綁指定不同的本地IP地址即可。這一般不用於TCP服務器。 SO_REUSEADDR允許完全重複的捆綁:當一個IP地址和端口綁定到某個套接口上時,還允許此IP地址和端口捆綁到另一個套接口上。一般來說,這個特性僅在支持多播的系統上纔有,而且只對UDP套接口而言(TCP不支持多播)
5.2 ChannelOption.SO_RCVBUF AND ChannelOption.SO_SNDBUF 定義接收或者傳輸的系統緩衝區buf的大小,
5.3 ChannelOption.ALLOCATOR Netty4使用對象池,重用緩衝區
bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
bootstrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);