SCX TCP 是一个极简 TCP 抽象库。
它提供了非常薄的一层 TCP Server 和 TCP Client 封装,用来简化 ServerSocket、Socket 的创建、监听、连接和回调处理。
SCX TCP 本身不是网络框架,也不是协议框架。它不理解 HTTP、WebSocket、MQTT 或其它任何应用层协议。
它只负责:
TCP Server 绑定端口
TCP Server 接受连接
TCP Server 将 Socket 交给用户处理器
TCP Client 连接远程地址
少量 TLS 辅助能力
当前版本为 0.2.0。
<dependency>
<groupId>dev.scx</groupId>
<artifactId>scx-tcp</artifactId>
<version>0.2.0</version>
</dependency>
SCX TCP 依赖 scx-function。
这个依赖主要用于 onConnect(...) 回调,使连接处理器可以直接抛出受检异常,而不需要强行包装成 RuntimeException。
SCX TCP 中最核心的概念包括:
ScxTCPServer TCP Server 抽象接口
TCPServer ScxTCPServer 的默认实现
TCPServerOptions TCP Server 构造选项
ScxTCPClient TCP Client 抽象接口
TCPClient ScxTCPClient 的默认实现
TLS TLS 辅助接口
TLSHelper SSLContext 创建工具
它们之间的关系可以简单理解为:
TCPServer
↓
绑定 ServerSocket
↓
循环 accept()
↓
每个 Socket 交给 onConnect 处理器
↓
每个连接使用一个虚拟线程处理
客户端部分更简单:
TCPClient
↓
new Socket()
↓
socket.connect(endpoint, timeout)
↓
返回 Socket
也就是说:
TCPServer 负责接收连接
TCPClient 负责建立连接
Socket 的读写和关闭由用户自己负责
import dev.scx.tcp.TCPServer;
import java.io.BufferedReader;
import java.io.InputStreamReader;
var tcpServer = new TCPServer();
tcpServer.onConnect(socket -> {
System.out.println("客户端连接了: " + socket.getRemoteSocketAddress());
try (socket) {
var reader = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
while (true) {
var line = reader.readLine();
if (line == null) {
break;
}
System.out.println(socket.getRemoteSocketAddress() + " : " + line);
}
}
System.out.println("连接结束");
});
tcpServer.start(8899);
System.out.println("已监听端口号: " + tcpServer.localAddress().getPort());
这里需要注意:
onConnect(...) 必须在 start(...) 前设置。start(...) 只负责开始监听。onConnect(...) 处理。Socket 的读写和关闭由 onConnect(...) 内部自己负责。TCPServer 不会替用户关闭已经交付出去的 Socket。import dev.scx.tcp.TCPClient;
import java.net.InetSocketAddress;
var tcpClient = new TCPClient();
try (var socket = tcpClient.connect(new InetSocketAddress("127.0.0.1", 8899))) {
var out = socket.getOutputStream();
out.write("hello\r\n".getBytes());
out.write("world\r\n".getBytes());
}
带连接超时:
var socket = tcpClient.connect(
new InetSocketAddress("127.0.0.1", 8899),
3000
);
超时时间单位来自 JDK Socket#connect(SocketAddress, int),也就是毫秒。
ScxTCPServer 是 TCP Server 抽象接口。
接口可以理解为:
public interface ScxTCPServer {
ScxTCPServer onConnect(Function1Void connectHandler);
void start(SocketAddress localAddress) throws IOException;
void stop();
InetSocketAddress localAddress();
default void start(int port) throws IOException {
start(new InetSocketAddress(port));
}
}
它的职责非常明确:
绑定端口
等待 TCP 连接
连接建立后,把 Socket 交给用户处理器
它不负责:
连接池
连接状态管理
连接数量统计
连接超时控制
协议解析
协议防护
流量控制
应用层调度
优雅关闭已建立连接
TCPServer 是 ScxTCPServer 的默认实现。
创建方式:
var server = new TCPServer();
带选项:
var options = new TCPServerOptions()
.backlog(256);
var server = new TCPServer(options);
内部使用的是 JDK ServerSocket。
启动时大致流程是:
1. 检查 server 是否已经运行
2. 检查是否设置了 connectHandler
3. 创建 ServerSocket
4. bind(localAddress, backlog)
5. 标记 running = true
6. 创建监听线程
7. 监听线程循环 accept()
8. 每个连接交给一个虚拟线程处理
onConnect(...) 用于设置连接处理器。
server.onConnect(socket -> {
// 处理 socket
});
连接处理器接收的是 JDK 原生 Socket。
Socket
SCX TCP 不包装这个 Socket,也不替它定义额外协议。
因此你可以直接使用:
socket.getInputStream()
socket.getOutputStream()
socket.getRemoteSocketAddress()
socket.getLocalSocketAddress()
socket.close()
示例:
server.onConnect(socket -> {
try (socket) {
var input = socket.getInputStream();
var output = socket.getOutputStream();
var bytes = input.readNBytes(1024);
output.write(bytes);
}
});
onConnect(...) 接收的是 Function1Void。
因此连接处理器可以直接抛出受检异常。
server.onConnect(socket -> {
try (socket) {
var input = socket.getInputStream();
if (input.read() == -1) {
throw new IOException("客户端已关闭");
}
}
});
不需要写成:
throw new RuntimeException(e);
这也是 scx-function 在这里的作用。
如果 connectHandler 抛出异常,TCPServer 不会吞掉异常,也不会额外提供 onError 回调。
当前实现会把异常显式移交给当前线程的 UncaughtExceptionHandler。
也就是说,语义上尽量接近:
这个连接处理线程自然失败
这样做的目的有几个:
onConnect(...) 内部自行决定是否捕获异常。如果需要自定义异常处理,可以在 onConnect(...) 内部自己写 try/catch。
server.onConnect(socket -> {
try (socket) {
handle(socket);
} catch (Throwable e) {
logError(socket, e);
}
});
TCPServer 把 Socket 交给 onConnect(...) 后,就不再管理这个连接。
因此推荐在处理器内部使用 try-with-resources:
server.onConnect(socket -> {
try (socket) {
// 读写 socket
}
});
如果不关闭 Socket,连接可能一直占用系统资源。
需要特别注意:
TCPServer.stop() 不会关闭已经交给 connectHandler 的 Socket
因为已经建立的连接属于用户处理器。
TCP Server 层无法知道什么叫“优雅关闭连接”。
这个语义只能由协议层或业务层定义。
start(...) 用于启动 TCP Server。
按端口启动:
server.start(8899);
按地址启动:
server.start(new InetSocketAddress("127.0.0.1", 8899));
也可以绑定到任意可用端口:
server.start(0);
int port = server.localAddress().getPort();
如果 server 已经运行,再次调用 start(...) 会抛出:
IllegalStateException
如果没有设置 connectHandler,调用 start(...) 也会抛出:
IllegalStateException
localAddress() 返回当前 server 绑定的本地地址。
InetSocketAddress address = server.localAddress();
System.out.println(address.getHostString());
System.out.println(address.getPort());
常见用途是获取自动分配端口:
server.start(0);
int port = server.localAddress().getPort();
如果 server 没有启动,调用 localAddress() 会抛出:
IllegalStateException
stop() 用于停止 TCP Server。
server.stop();
它的语义非常明确:
停止接受新的 TCP 连接
不干涉已经建立的连接
当前实现大致会:
1. running = false
2. 关闭 ServerSocket
3. accept() 因 ServerSocket 关闭而退出
4. 等待监听线程结束
5. 清空 serverSocket 和 listenThread
如果 server 本来没有运行,调用 stop() 会直接返回。
server.stop();
server.stop();
第二次调用不会做任何事情。
stop() 只停止监听。
它不会关闭已经交付给 onConnect(...) 的连接。
例如:
server.onConnect(socket -> {
try (socket) {
Thread.sleep(60_000);
}
});
如果一个连接已经进入处理器,此时调用:
server.stop();
这个连接处理器仍然会继续运行,直到它自己结束。
这是刻意设计。
因为已经建立的连接属于协议层或业务层,TCP 接受器不应该越权干涉。
TCPServerOptions 承载 TCP Server 构造期的少量配置。
当前唯一选项是:
backlog
创建:
var options = new TCPServerOptions();
设置 backlog:
var options = new TCPServerOptions()
.backlog(256);
默认值是:
128
复制构造:
var copy = new TCPServerOptions(options);
backlog 会传给:
ServerSocket#bind(SocketAddress endpoint, int backlog)
它表示服务端 socket 的 listen 队列长度提示。
示例:
var server = new TCPServer(
new TCPServerOptions().backlog(512)
);
需要注意:
backlog 的实际行为由操作系统决定。如果需要连接数限制、限流或协议级超时,应在更高层实现。
TCPServer 的并发模型非常简单:
一个监听线程
多个连接处理虚拟线程
监听线程:
Thread.ofPlatform()
每个连接处理线程:
Thread.ofVirtual()
也就是说:
监听 accept 使用平台线程
处理连接使用虚拟线程
每次成功 accept() 后,都会创建一个新的虚拟线程执行 connectHandler。
accept()
↓
Thread.ofVirtual().start(() -> handle(socket))
SCX TCP 的定位是极简 TCP 接受器。
使用虚拟线程可以让每个连接仍然写成阻塞式代码。
例如:
server.onConnect(socket -> {
try (socket) {
var reader = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
while (true) {
var line = reader.readLine();
if (line == null) {
break;
}
handleLine(line);
}
}
});
代码保持同步、直接、易读。
SCX TCP 不提供事件循环,也不提供异步回调模型。
SCX TCP 不跟踪虚拟线程。
它不会统计:
当前连接数
当前虚拟线程数
已完成连接数
失败连接数
也不会主动中断虚拟线程。
因此如果你需要这些能力,应在 onConnect(...) 内部自己实现。
示例:
var activeConnections = new AtomicInteger();
server.onConnect(socket -> {
activeConnections.incrementAndGet();
try (socket) {
handle(socket);
} finally {
activeConnections.decrementAndGet();
}
});
SCX TCP 刻意不提供 maxConcurrentConnections。
原因是:
TCPServer 能干涉的连接已经是三次握手成功后的连接
它无法防止半连接攻击。
真正的 TCP 层防护通常属于:
操作系统
内核参数
防火墙
负载均衡
云厂商安全服务
协议层防护则属于:
HTTP 层
WebSocket 层
自定义协议层
业务层
例如 Slowloris 这类攻击,需要在协议层或业务层处理超时和读取策略。
TCP 接受器本身不应该理解这些协议语义。
SCX TCP 不提供连接级读取超时或写入超时管理。
因为 TCP Server 只负责把 Socket 交给用户。
如果需要读取超时,可以在处理器中使用:
socket.setSoTimeout(10_000);
示例:
server.onConnect(socket -> {
try (socket) {
socket.setSoTimeout(10_000);
var reader = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
var line = reader.readLine();
if (line != null) {
handleLine(line);
}
}
});
连接超时、读取超时、协议超时都应该由使用者根据协议需要自行设置。
ScxTCPServer 没有 onError 回调。
TCP Server 层面的异常大致分两类。
第一类是系统异常。
例如:
accept 异常
ServerSocket 被强制关闭
系统资源耗尽
这类异常通常没有足够上下文让用户处理。
当前实现会记录日志并关闭监听。
第二类是用户处理器异常。
例如:
onConnect 中读取失败
业务处理失败
协议解析失败
这些异常最适合由用户在 onConnect(...) 内部处理。
如果额外提供 onError,反而容易让异常处理路径变复杂。
因此当前设计是:
系统异常内部记录
处理器异常移交 UncaughtExceptionHandler
自定义处理请在 onConnect 内部完成
ScxTCPClient 是 TCP Client 抽象接口。
接口可以理解为:
public interface ScxTCPClient {
Socket connect(SocketAddress endpoint, int timeout) throws IOException;
default Socket connect(SocketAddress endpoint) throws IOException {
return connect(endpoint, 0);
}
}
它只负责建立 TCP 连接。
它不负责:
协议握手
请求发送
响应读取
连接池
重连
心跳
超时策略
这些都属于上层逻辑。
TCPClient 是 ScxTCPClient 的默认实现。
实现非常直接:
public final class TCPClient implements ScxTCPClient {
@Override
public Socket connect(SocketAddress endpoint, int timeout) throws IOException {
var tcpSocket = new Socket();
tcpSocket.connect(endpoint, timeout);
return tcpSocket;
}
}
也就是说,TCPClient 只是 Socket#connect(...) 的结构化封装。
var client = new TCPClient();
var socket = client.connect(
new InetSocketAddress("127.0.0.1", 8899)
);
使用完后应该关闭:
try (var socket = client.connect(new InetSocketAddress("127.0.0.1", 8899))) {
var out = socket.getOutputStream();
out.write("hello\r\n".getBytes());
}
带连接超时:
try (var socket = client.connect(
new InetSocketAddress("127.0.0.1", 8899),
3000
)) {
// 使用 socket
}
下面是一个完整 echo server。
import dev.scx.tcp.TCPServer;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class EchoServer {
public static void main(String[] args) throws Exception {
var server = new TCPServer();
server.onConnect(socket -> {
try (socket) {
var reader = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
var writer = new PrintWriter(
socket.getOutputStream(),
true
);
while (true) {
var line = reader.readLine();
if (line == null) {
break;
}
writer.println("echo: " + line);
}
}
});
server.start(8899);
System.out.println("Echo server started: " + server.localAddress());
}
}
import dev.scx.tcp.TCPClient;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
public class EchoClient {
public static void main(String[] args) throws Exception {
var client = new TCPClient();
try (var socket = client.connect(new InetSocketAddress("127.0.0.1", 8899))) {
var reader = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
var writer = new PrintWriter(
socket.getOutputStream(),
true
);
writer.println("hello");
var response = reader.readLine();
System.out.println(response);
}
}
}
输出:
echo: hello
下面示例会启动多个虚拟线程客户端,同时连接同一个 server。
import dev.scx.tcp.TCPClient;
import java.net.InetSocketAddress;
for (int j = 0; j < 10; j = j + 1) {
Thread.ofVirtual().start(() -> {
var tcpClient = new TCPClient();
try (var socket = tcpClient.connect(new InetSocketAddress("127.0.0.1", 8899))) {
var out = socket.getOutputStream();
for (int i = 0; i < 10000; i = i + 1) {
out.write((i + "\r\n").getBytes());
}
} catch (Exception e) {
e.printStackTrace();
}
});
}
这个示例展示的是:
TCPServer 每个连接一个虚拟线程
TCPClient 返回原生 Socket
具体写入逻辑由用户处理
scx-tcp 提供了一个轻量 TLS 辅助接口。
import dev.scx.tcp.tls.TLS;
它主要包装:
SSLContext
SSLServerSocketFactory
SSLSocketFactory
接口可以理解为:
public interface TLS {
static TLS of(SSLContext sslContext);
static TLS of(Path path, String password);
static TLS ofDefault();
static TLS ofTrustAny();
SSLContext sslContext();
SSLServerSocketFactory serverSocketFactory();
SSLSocketFactory socketFactory();
default SSLSocket upgradeToTLS(Socket tcpSocket) throws IOException;
}
需要注意:
TCPServer 默认使用的是普通 ServerSocket
TLS 只是辅助能力,不会自动改变 TCPServer 的行为
如果你需要 TLS,需要在合适的位置显式使用 TLS 相关能力。
如果你已经有 SSLContext,可以直接创建 TLS。
SSLContext sslContext = ...;
TLS tls = TLS.of(sslContext);
然后可以获取:
tls.sslContext();
tls.socketFactory();
tls.serverSocketFactory();
可以从 keystore 文件创建 TLS。
import dev.scx.tcp.tls.TLS;
import java.nio.file.Path;
var tls = TLS.of(
Path.of("server.p12"),
"changeit"
);
内部大致流程是:
1. 从 path 和 password 创建 KeyStore
2. 创建 KeyManagerFactory
3. 创建 TrustManagerFactory
4. 创建 SSLContext("TLS")
5. 初始化 SSLContext
6. 返回 TLSImpl
这种方式适合服务端或需要指定证书的场景。
TLS.ofDefault() 会使用系统默认信任证书创建 TLS。
var tls = TLS.ofDefault();
var socketFactory = tls.socketFactory();
这更常用于客户端访问公开可信证书服务。
例如:
try (var socket = tls.socketFactory().createSocket("example.com", 443)) {
// 使用 SSLSocket
}
TLS.ofTrustAny() 会创建一个忽略证书校验的 SSLContext。
var tls = TLS.ofTrustAny();
它适合测试环境,例如自签名证书测试。
不推荐用于生产环境。
TrustAny 会跳过服务端证书验证
生产环境使用会带来严重安全风险
upgradeToTLS(...) 可以把已有 Socket 包装为 SSLSocket。
var tls = TLS.ofDefault();
try (var tcpSocket = new TCPClient().connect(address)) {
var sslSocket = tls.upgradeToTLS(tcpSocket);
sslSocket.startHandshake();
// 使用 sslSocket 读写
}
需要注意:
upgradeToTLS(...) 只是把已有 socket 包装为 SSLSocket。startHandshake() 由调用方决定。TCPServer 变成 TLS Server。下面是一个普通 TLS client 示例。
import dev.scx.tcp.tls.TLS;
var tls = TLS.ofDefault();
try (var socket = tls.socketFactory().createSocket("example.com", 443)) {
var sslSocket = (SSLSocket) socket;
sslSocket.startHandshake();
var out = sslSocket.getOutputStream();
var in = sslSocket.getInputStream();
out.write("""
GET / HTTP/1.1\r
Host: example.com\r
Connection: close\r
\r
""".getBytes());
var bytes = in.readAllBytes();
System.out.println(new String(bytes));
}
如果是测试自签名证书:
var tls = TLS.ofTrustAny();
但生产环境不应使用 ofTrustAny()。
如果需要自己创建 SSLServerSocket,可以使用:
import dev.scx.tcp.tls.TLS;
import java.nio.file.Path;
var tls = TLS.of(Path.of("server.p12"), "changeit");
try (var serverSocket = tls.serverSocketFactory().createServerSocket(8443)) {
while (true) {
var socket = serverSocket.accept();
Thread.ofVirtual().start(() -> {
try (socket) {
// 处理 TLS socket
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
这段代码没有使用 TCPServer。
因为当前 TCPServer 固定使用普通 ServerSocket。
如果需要完整 TLS Server,可以直接使用 TLS#serverSocketFactory() 自己构建。
SCX TCP 的设计边界非常严格。
它只做 TCP 接受器应该做的事。
绑定端口
accept
交付 Socket
停止 accept
它不做:
连接管理
协议解析
连接池
读写封装
心跳
重试
限流
统计
超时策略
异常回调
业务调度
这些能力应该放在更高层。
例如:
scx-http-x 可以基于 scx-tcp 实现 HTTP Server
自定义协议层 可以基于 scx-tcp 处理协议帧
业务层 可以决定连接生命周期和资源管理
scx-tcp 是更底层的 TCP 能力。
上层 HTTP 实现可以基于它构建。
可以理解为:
scx-tcp
提供 Socket accept / connect
scx-http-x
基于 TCP Socket 实现 HTTP/1.1 读写、路由、SSE、Upgrade 等能力
因此,如果你需要写 HTTP 服务,通常不直接使用 scx-tcp。
如果你要实现自定义 TCP 协议、协议网关、简单 socket 工具,才适合直接使用 scx-tcp。
SCX TCP 没有隐藏 JDK Socket。
这是刻意设计。
因为 TCP 层最重要的对象就是:
Socket
把它交给用户后,用户可以完整控制:
输入流
输出流
超时
关闭
半关闭
TCP 参数
协议解析
错误处理
例如:
socket.setSoTimeout(10_000);
socket.setTcpNoDelay(true);
socket.shutdownOutput();
这些都可以直接使用 JDK 原生 API。
Server 应在应用关闭时调用:
server.stop();
示例:
var server = new TCPServer();
Runtime.getRuntime().addShutdownHook(new Thread(server::stop));
连接处理器内部应关闭 socket:
server.onConnect(socket -> {
try (socket) {
handle(socket);
}
});
客户端也应关闭 socket:
try (var socket = client.connect(address)) {
// 使用 socket
}
在简单程序中,可以让处理器异常交给默认线程异常处理器。
server.onConnect(socket -> {
try (socket) {
handle(socket);
}
});
在生产程序中,更推荐在处理器内部捕获并记录。
server.onConnect(socket -> {
try (socket) {
handle(socket);
} catch (Throwable e) {
logger.log(ERROR, "连接处理失败: " + socket.getRemoteSocketAddress(), e);
}
});
原因是:
TCPServer 不理解业务语义
只有 onConnect 内部知道这个异常应该如何处理
import dev.scx.tcp.TCPServer;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.CountDownLatch;
public class StoppableServer {
public static void main(String[] args) throws Exception {
var server = new TCPServer();
server.onConnect(socket -> {
try (socket) {
var reader = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
while (true) {
var line = reader.readLine();
if (line == null) {
break;
}
System.out.println(line);
}
}
});
server.start(8899);
Runtime.getRuntime().addShutdownHook(new Thread(server::stop));
System.out.println("server started at " + server.localAddress());
new CountDownLatch(1).await();
}
}
import dev.scx.tcp.TCPServer;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class TimeoutServer {
public static void main(String[] args) throws Exception {
var server = new TCPServer();
server.onConnect(socket -> {
try (socket) {
socket.setSoTimeout(10_000);
var reader = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
var line = reader.readLine();
if (line == null) {
return;
}
System.out.println("收到: " + line);
}
});
server.start(8899);
}
}
这里的超时策略属于协议层或业务层,因此放在 onConnect(...) 内部。
import dev.scx.tcp.TCPServer;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class TextProtocolServer {
public static void main(String[] args) throws Exception {
var server = new TCPServer();
server.onConnect(socket -> {
try (socket) {
var reader = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
var writer = new PrintWriter(
socket.getOutputStream(),
true
);
while (true) {
var line = reader.readLine();
if (line == null) {
break;
}
if (line.equals("PING")) {
writer.println("PONG");
} else if (line.equals("QUIT")) {
writer.println("BYE");
break;
} else {
writer.println("UNKNOWN");
}
}
}
});
server.start(8899);
}
}
客户端:
import dev.scx.tcp.TCPClient;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
public class TextProtocolClient {
public static void main(String[] args) throws Exception {
var client = new TCPClient();
try (var socket = client.connect(new InetSocketAddress("127.0.0.1", 8899))) {
var reader = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
var writer = new PrintWriter(
socket.getOutputStream(),
true
);
writer.println("PING");
System.out.println(reader.readLine());
writer.println("QUIT");
System.out.println(reader.readLine());
}
}
}
ScxTCPServer 的职责边界严格等同于一个结构化 accept 循环。
它不是:
服务器框架
连接管理器
协议框架
任务调度器
安全网关
它只是更方便地写:
while (true) {
var socket = serverSocket.accept();
handle(socket);
}
一旦连接被 accept,Socket 就会传给 connectHandler。
此后,连接生命周期由用户处理。
读
写
关闭
超时
异常处理
协议解析
都属于用户逻辑。
stop() 不关闭已建立连接。
因为 TCP 接受器无法知道已建立连接应该如何结束。
例如 HTTP、WebSocket、数据库协议、自定义协议都有不同的关闭语义。
onError 会制造第二条异常通道。
系统异常通常无法恢复。
业务异常应该在 onConnect(...) 内部处理。
因此 SCX TCP 不暴露 onError。
连接数量限制不属于这个层次。
如果要防护 TCP 层攻击,应使用操作系统、防火墙或基础设施。
如果要防护协议层攻击,应在协议处理器中实现。
SCX TCP 的默认模型是:
一个连接一个虚拟线程
这让用户可以写阻塞式 I/O 代码,而不需要事件循环。
TLS 模块提供 SSLContext 和 socket factory 的创建辅助。
但它不会自动改变 TCPServer 的工作方式。
普通 TCPServer 仍然是普通 TCP Server。
不是。
它只是 TCP Server / TCP Client 的极简封装。
不会。
它只把 Socket 交给 onConnect(...)。
协议解析由用户自己做。
每个连接使用一个新的虚拟线程处理。
监听 accept 使用平台线程。
不会。
Socket 交给 onConnect(...) 后,由用户负责关闭。
推荐写法:
server.onConnect(socket -> {
try (socket) {
handle(socket);
}
});
不会。
stop() 只停止接受新连接。
已经交给处理器的连接继续运行。
可以。
int port = server.localAddress().getPort();
这对 start(0) 很有用。
是的。
否则会抛出 IllegalStateException。
不可以。
已经运行时再次调用 start(...) 会抛出 IllegalStateException。
可以。
如果 server 没有运行,stop() 直接返回。
不是。
它只是传给 ServerSocket#bind(...) 的 listen backlog。
实际含义和效果由操作系统决定。
不支持。
如果需要限制连接数,应在 onConnect(...) 或更高层实现。
不直接支持。
可以在 onConnect(...) 中对 Socket 设置:
socket.setSoTimeout(...)
支持。
client.connect(address, timeout)
不传 timeout 时使用默认值:
0
不会。
重连属于上层策略。
没有。
每次 connect(...) 返回一个新的 Socket。
可以。
因为 onConnect(...) 使用的是 Function1Void。
异常会被移交给当前线程的 UncaughtExceptionHandler。
如果需要自定义处理,应在 onConnect(...) 内部捕获。
不会主动解释或处理用户处理器异常。
系统级 accept 异常会由内部日志记录。
提供 TLS 辅助工具。
但 TCPServer 本身默认仍然是普通 TCP Server。
如果需要 TLS,需要显式使用 TLS 的 SSLSocketFactory 或 SSLServerSocketFactory。
不应该。
它会忽略证书验证,只适合测试环境。
不会明确替你完成所有 TLS 流程。
通常你应根据场景调用:
sslSocket.startHandshake();
并配置 client/server mode 等参数。
适合:
自定义 TCP 协议
简单 socket 工具
本地 TCP 测试
作为更高层协议库的底层 accept/connect 能力
不适合直接承担:
HTTP 框架
WebSocket 框架
连接池
负载均衡
限流系统
安全网关
复杂协议服务器
因为 TCP 层只应该做 TCP 层的事。
一旦加入协议语义、连接统计、限流、错误回调、优雅关闭等能力,这个库就会变成服务器框架。
SCX TCP 刻意保持最小边界,让上层模块自己定义语义。