java 网络编程核心是基于 socket 实现传输层通信(tcp/udp),基于标准库 / 框架实现应用层协议(http/websocket),覆盖基础通信、生产环境高可用、并发、异常处理、资源释放等全场景。
一、核心基础概念
- tcp:面向连接、可靠、有序、字节流传输(如:文件传输、接口调用)
- udp:无连接、不可靠、快速、数据报传输(如:直播、实时消息)
- http:应用层协议,基于 tcp,短连接 / 长连接(web 接口、网页)
- websocket:基于 tcp 的全双工长连接,解决 http 轮询弊端(实时通信)
- socket:java 网络编程的基石,是ip + 端口的抽象,分为:
serversocket:服务端,监听端口等待连接socket:客户端,主动发起连接
代码概括:
二、传输层编程:tcp(生产级)
基础原理
- 三次握手建立连接,四次挥手断开
- 可靠传输:超时重传、拥塞控制、顺序保证
- 适合:需要数据不丢失、不乱序的场景
生产级 tcp 服务端(线程池 + 心跳 + 优雅关闭)
核心优化:
- 线程池异步处理客户端,避免单线程阻塞
- 心跳机制检测死连接
- 优雅关闭:释放端口、关闭线程池、中断线程
- 全局异常捕获 + 日志
- 配置化端口、超时时间
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import java.io.*;
import java.net.serversocket;
import java.net.socket;
import java.util.concurrent.executorservice;
import java.util.concurrent.executors;
import java.util.concurrent.timeunit;
/**
* 生产级 tcp 服务端
*/
public class tcpserver {
private static final logger log = loggerfactory.getlogger(tcpserver.class);
// 配置化参数(可抽取到配置文件)
private static final int port = 9999;
private static final int so_timeout = 30000; // 30秒无心跳断开
private static final int core_pool_size = 10;
private final executorservice threadpool = executors.newfixedthreadpool(core_pool_size);
private serversocket serversocket;
private volatile boolean isrunning = true;
public static void main(string[] args) {
new tcpserver().start();
}
/**
* 启动服务端
*/
public void start() {
try {
serversocket = new serversocket(port);
log.info("tcp 服务端启动成功,端口:{}", port);
// 注册优雅关闭钩子
runtime.getruntime().addshutdownhook(new thread(this::shutdown));
while (isrunning) {
// 阻塞等待客户端连接
socket clientsocket = serversocket.accept();
log.info("客户端连接成功:{}:{}", clientsocket.getinetaddress(), clientsocket.getport());
// 线程池处理客户端请求
threadpool.execute(new clienthandler(clientsocket));
}
} catch (exception e) {
if (isrunning) {
log.error("tcp 服务端异常", e);
}
}
}
/**
* 优雅关闭
*/
public void shutdown() {
try {
isrunning = false;
if (serversocket != null && !serversocket.isclosed()) {
serversocket.close();
}
threadpool.shutdown();
if (!threadpool.awaittermination(5, timeunit.seconds)) {
threadpool.shutdownnow();
}
log.info("tcp 服务端已优雅关闭");
} catch (exception e) {
log.error("服务端关闭异常", e);
}
}
/**
* 客户端处理器(生产级:心跳、异常处理、资源释放)
*/
private static class clienthandler implements runnable {
private final socket socket;
private bufferedreader reader;
private bufferedwriter writer;
public clienthandler(socket socket) {
this.socket = socket;
try {
socket.setsotimeout(so_timeout); // 读超时(心跳检测)
reader = new bufferedreader(new inputstreamreader(socket.getinputstream()));
writer = new bufferedwriter(new outputstreamwriter(socket.getoutputstream()));
} catch (exception e) {
close();
}
}
@override
public void run() {
try {
string msg;
while ((msg = reader.readline()) != null) {
log.info("收到客户端消息:{}", msg);
// 心跳包处理
if ("heartbeat".equals(msg)) {
sendmsg("heartbeat_ack");
continue;
}
// 业务消息处理
string resp = "服务端已接收:" + msg;
sendmsg(resp);
}
} catch (exception e) {
log.warn("客户端连接异常:{}", e.getmessage());
} finally {
close();
}
}
/**
* 发送消息
*/
private void sendmsg(string msg) throws ioexception {
writer.write(msg + "\n");
writer.flush();
}
/**
* 统一释放资源
*/
private void close() {
try {
if (reader != null) reader.close();
if (writer != null) writer.close();
if (socket != null && !socket.isclosed()) socket.close();
log.info("客户端连接已关闭:{}:{}", socket.getinetaddress(), socket.getport());
} catch (exception e) {
log.error("资源释放异常", e);
}
}
}
}生产级 tcp 客户端(重连 + 心跳 + 异步发送)
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import java.io.*;
import java.net.socket;
import java.util.concurrent.executors;
import java.util.concurrent.scheduledexecutorservice;
import java.util.concurrent.timeunit;
/**
* 生产级 tcp 客户端(自动重连+心跳)
*/
public class tcpclient {
private static final logger log = loggerfactory.getlogger(tcpclient.class);
private static final string server_host = "127.0.0.1";
private static final int server_port = 9999;
private static final int heartbeat_interval = 5; // 5秒心跳
private static final int reconnect_interval = 3; // 3秒重连
private socket socket;
private bufferedreader reader;
private bufferedwriter writer;
private volatile boolean isconnected = false;
private final scheduledexecutorservice scheduler = executors.newscheduledthreadpool(1);
public static void main(string[] args) {
tcpclient client = new tcpclient();
client.connect();
// 测试发送消息
client.sendmsg("hello tcp server");
}
/**
* 建立连接(失败自动重连)
*/
public void connect() {
while (!isconnected) {
try {
socket = new socket(server_host, server_port);
reader = new bufferedreader(new inputstreamreader(socket.getinputstream()));
writer = new bufferedwriter(new outputstreamwriter(socket.getoutputstream()));
isconnected = true;
log.info("连接服务端成功");
// 启动心跳
startheartbeat();
// 监听服务端消息
new thread(this::listenservermsg).start();
} catch (exception e) {
log.error("连接失败,{}秒后重试...", reconnect_interval);
try {
timeunit.seconds.sleep(reconnect_interval);
} catch (interruptedexception ignored) {}
}
}
}
/**
* 心跳机制
*/
private void startheartbeat() {
scheduler.scheduleatfixedrate(() -> {
try {
if (isconnected) {
sendmsg("heartbeat");
log.debug("发送心跳包");
}
} catch (exception e) {
log.error("心跳异常,开始重连");
disconnect();
connect();
}
}, 0, heartbeat_interval, timeunit.seconds);
}
/**
* 监听服务端消息
*/
private void listenservermsg() {
try {
string msg;
while ((msg = reader.readline()) != null) {
log.info("收到服务端消息:{}", msg);
}
} catch (exception e) {
log.warn("与服务端断开连接");
disconnect();
connect();
}
}
/**
* 发送消息(线程安全)
*/
public synchronized void sendmsg(string msg) {
if (!isconnected) {
log.warn("未连接服务端,消息发送失败:{}", msg);
return;
}
try {
writer.write(msg + "\n");
writer.flush();
} catch (exception e) {
log.error("消息发送异常", e);
disconnect();
connect();
}
}
/**
* 断开连接
*/
private void disconnect() {
isconnected = false;
try {
if (reader != null) reader.close();
if (writer != null) writer.close();
if (socket != null) socket.close();
} catch (exception ignored) {}
}
}三、传输层编程:udp(生产级)
基础原理
- 无连接,直接发送数据报
- 速度快,不保证可靠
- 适合:实时性要求高、可容忍少量丢包的场景
生产级 udp 服务端 + 客户端
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import java.net.datagrampacket;
import java.net.datagramsocket;
import java.net.inetaddress;
import java.util.concurrent.executorservice;
import java.util.concurrent.executors;
/**
* 生产级 udp(服务端+客户端合一)
*/
public class udpserverclient {
private static final logger log = loggerfactory.getlogger(udpserverclient.class);
private static final int port = 9998;
private static final int buffer_size = 1024;
private final executorservice threadpool = executors.newsinglethreadexecutor();
public static void main(string[] args) {
udpserverclient udp = new udpserverclient();
udp.startserver();
udp.sendclientmsg("127.0.0.1", "hello udp server");
}
// ==================== udp 服务端 ====================
public void startserver() {
threadpool.execute(() -> {
try (datagramsocket socket = new datagramsocket(port)) {
log.info("udp 服务端启动,端口:{}", port);
byte[] buffer = new byte[buffer_size];
while (true) {
datagrampacket packet = new datagrampacket(buffer, buffer.length);
socket.receive(packet); // 阻塞接收
string msg = new string(packet.getdata(), 0, packet.getlength());
log.info("收到udp消息:{} 来自:{}:{}",
msg, packet.getaddress(), packet.getport());
// 回写消息
string resp = "udp 已接收:" + msg;
sendudpmsg(socket, packet.getaddress(), packet.getport(), resp);
}
} catch (exception e) {
log.error("udp 服务端异常", e);
}
});
}
// ==================== udp 客户端发送 ====================
public void sendclientmsg(string host, string msg) {
try (datagramsocket socket = new datagramsocket()) {
inetaddress address = inetaddress.getbyname(host);
sendudpmsg(socket, address, port, msg);
log.info("udp 客户端发送消息:{}", msg);
} catch (exception e) {
log.error("udp 客户端发送异常", e);
}
}
/**
* 统一发送 udp 消息
*/
private void sendudpmsg(datagramsocket socket, inetaddress addr, int port, string msg) throws exception {
byte[] data = msg.getbytes();
datagrampacket packet = new datagrampacket(data, data.length, addr, port);
socket.send(packet);
}
}四、应用层编程:http(生产级)
java 生产环境绝不使用原生 httpurlconnection,推荐两款标准框架:
- okhttp:轻量、稳定、android / 后端通用
- resttemplate:spring 生态标准(微服务首选)
1. okhttp 生产级 http 工具类
依赖:
<dependency>
<groupid>com.squareup.okhttp3</groupid>
<artifactid>okhttp</artifactid>
<version>4.12.0</version>
</dependency>生产级代码(连接池、超时、重试、单例):
import okhttp3.*;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import java.util.concurrent.timeunit;
/**
* 生产级 okhttp 工具类(单例+连接池)
*/
public class okhttputil {
private static final logger log = loggerfactory.getlogger(okhttputil.class);
private static final okhttpclient client;
private static final int max_idle_connections = 20;
private static final long keep_alive_duration = 5l;
// 单例 okhttpclient(关键:okhttp 必须单例,复用连接池)
static {
client = new okhttpclient.builder()
.connecttimeout(5, timeunit.seconds)
.readtimeout(10, timeunit.seconds)
.writetimeout(10, timeunit.seconds)
.connectionpool(new connectionpool(max_idle_connections, keep_alive_duration, timeunit.minutes))
.retryonconnectionfailure(true) // 自动重试
.build();
}
private okhttputil() {}
/**
* get 请求
*/
public static string get(string url) throws exception {
request request = new request.builder()
.url(url)
.addheader("content-type", "application/json")
.build();
try (response response = client.newcall(request).execute()) {
if (!response.issuccessful()) {
throw new exception("http 请求失败,状态码:" + response.code());
}
return response.body().string();
}
}
/**
* post json 请求
*/
public static string postjson(string url, string json) throws exception {
requestbody body = requestbody.create(json, mediatype.parse("application/json; charset=utf-8"));
request request = new request.builder()
.url(url)
.post(body)
.build();
try (response response = client.newcall(request).execute()) {
if (!response.issuccessful()) {
throw new exception("http post 失败,状态码:" + response.code());
}
return response.body().string();
}
}
}2. spring resttemplate 生产级配置
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.http.client.clienthttprequestfactory;
import org.springframework.http.client.simpleclienthttprequestfactory;
import org.springframework.web.client.resttemplate;
/**
* spring 生产级 resttemplate 配置
*/
@configuration
public class resttemplateconfig {
@bean
public resttemplate resttemplate(clienthttprequestfactory factory) {
return new resttemplate(factory);
}
@bean
public clienthttprequestfactory clienthttprequestfactory() {
simpleclienthttprequestfactory factory = new simpleclienthttprequestfactory();
factory.setconnecttimeout(5000);
factory.setreadtimeout(10000);
// 生产环境可替换为 okhttp 工厂,性能更强
return factory;
}
}五、应用层编程:websocket(生产级)
基础原理
- 基于 tcp,全双工长连接
- 一次握手,永久通信,服务端可主动推送消息
- 适合:聊天、实时通知、大屏数据
spring boot 生产级 websocket
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-websocket</artifactid>
</dependency>生产级代码(集群可配合 redis 广播):
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.stereotype.component;
import javax.websocket.*;
import javax.websocket.server.serverendpoint;
import java.util.concurrent.copyonwritearrayset;
import java.util.concurrent.atomic.atomicinteger;
/**
* 生产级 websocket 服务端
*/
@component
@serverendpoint("/ws/server")
public class websocketserver {
private static final logger log = loggerfactory.getlogger(websocketserver.class);
// 在线连接数(线程安全)
private static final atomicinteger online_count = new atomicinteger(0);
// 客户端集合(线程安全)
private static final copyonwritearrayset<websocketserver> web_socket_set = new copyonwritearrayset<>();
private session session;
/**
* 连接建立成功
*/
@onopen
public void onopen(session session) {
this.session = session;
web_socket_set.add(this);
online_count.incrementandget();
log.info("新连接加入,当前在线:{}", online_count.get());
sendmessage("连接成功");
}
/**
* 连接关闭
*/
@onclose
public void onclose() {
web_socket_set.remove(this);
online_count.decrementandget();
log.info("连接关闭,当前在线:{}", online_count.get());
}
/**
* 收到客户端消息
*/
@onmessage
public void onmessage(string message, session session) {
log.info("收到消息:{}", message);
// 群发消息
sendtoall("服务端广播:" + message);
}
/**
* 异常处理
*/
@onerror
public void onerror(session session, throwable error) {
log.error("websocket 异常", error);
}
/**
* 发送消息
*/
public void sendmessage(string message) {
try {
this.session.getbasicremote().sendtext(message);
} catch (exception e) {
log.error("消息发送失败", e);
}
}
/**
* 群发消息(生产常用)
*/
public static void sendtoall(string message) {
for (websocketserver ws : web_socket_set) {
ws.sendmessage(message);
}
}
}启用 websocket:
import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.web.socket.config.annotation.enablewebsocket;
@springbootapplication
@enablewebsocket // 开启 websocket
public class nettyapplication {
public static void main(string[] args) {
springapplication.run(nettyapplication.class, args);
}
}六、生产环境核心最佳实践(必看)
- socket 必须单例 / 池化
- tcp 客户端、okhttp、resttemplate 禁止频繁创建对象,必须复用连接池
- 超时强制设置
- 连接超时、读超时、写超时,避免线程无限阻塞
- 优雅关闭
- 用
shutdownhook释放端口、线程池、socket,防止端口占用
- 用
- 心跳机制
- tcp/websocket 必须加心跳,检测死连接,释放资源
- 线程池替代多线程
- 禁止为每个客户端创建新线程,用线程池控制并发
- 异常全覆盖
- io 异常、连接异常、超时异常必须捕获,不能直接抛出
- 生产禁用原生 socket 高并发场景
- 高并发用 netty(nio 框架),性能提升 10~100 倍
由以上可总结出:
- 传输层:tcp 可靠(生产用线程池 + 心跳),udp 快速(实时场景)
- 应用层:http 用 okhttp/resttemplate,websocket 用 spring 封装
- 生产核心:连接池、超时、优雅关闭、心跳、异常处理
- 高并发方案:原生 socket 仅适合小并发,高并发必须用 netty
概念概括
一 java 网络编程本质就是两层:
- 传输层(tcp、udp)
- 基于 socket 编程
- 自己定义报文格式、粘包拆包、心跳、重连
- 应用层(http、https、websocket)
- 基于 tcp 封装好的协议
- 不用关心底层连接,只关心请求 / 响应
二、tcp、udp、http、websocket 核心区别对比表
| 对比项 | tcp | udp | http | websocket |
|---|---|---|---|---|
| 连接方式 | 面向连接(三次握手) | 无连接 | 基于 tcp,短 / 长连接 | 基于 tcp,全双工长连接 |
| 可靠性 | 可靠,不丢包、不乱序 | 不可靠,可能丢包、乱序 | 可靠(依赖 tcp) | 可靠(依赖 tcp) |
| 传输方式 | 字节流 | 数据报 | 请求 - 响应模型 | 全双工,双向主动推送 |
| 开销 | 高(握手、确认、重传) | 低 | 很高(header 大) | 中等(握手一次,后续帧很小) |
| 速度 | 较慢 | 极快 | 慢 | 快 |
| 消息边界 | 无边界 → 粘包拆包问题 | 有边界 → 不会粘包 | 协议自带边界 | 帧结构,自带边界 |
| 服务端推送 | 需自己实现 | 需自己实现 | 不能主动推送 | 支持主动推送 |
| 典型用途 | 文件传输、im、支付、长连接 | 直播、语音、游戏、dns | 接口、网页、restful | 聊天、大屏、实时通知、物联网 |
1. tcp(transmission control protocol)
特点
- 面向连接,可靠传输
- 有序、重传、流量控制、拥塞控制
- 字节流传输,没有消息边界
- 适合对数据完整性要求高的场景
生产注意事项(非常重要)
- 必须处理粘包 / 拆包tcp 是流,发送 2 次数据可能被合并成 1 次,或 1 次被拆成多段。解决方案:
- 固定长度
- 分隔符(\n、\r\n)
- 长度域 + 报文体(生产标准方案)
- 必须设置 so_timeout不设置会导致线程永久阻塞,oom 或线程耗尽
- 禁止每次 new socket必须复用连接、使用连接池
- 必须心跳保活nat 超时、防火墙会静默断开连接,应用层无感知
- 必须优雅关闭close () 要放在 finally,避免端口 time_wait 堆积
- 高并发不能用 bio并发 > 100 必须用 nio / netty,否则线程爆炸
2. udp(user datagram protocol)
特点
- 无连接,不握手,直接发
- 数据报模式,自带消息边界
- 速度极快,开销极小
- 不保证到达、顺序、重复
生产注意事项
- 不适合支付、交易、重要指令丢包就没了
- 适合实时性 > 可靠性直播、实时游戏、实时监控
- 无需处理粘包一个 datagrampacket 就是一个完整包
- 可以自己实现简单可靠机制序号 + 确认 + 重传(rtp 就是这么干的)
- 包大小不要超过 mtu一般 ≤ 1472 字节,否则会被 ip 层分片,更容易丢包
3. http(hypertext transfer protocol)
特点
- 应用层协议,基于 tcp
- 请求 - 响应模型:客户端问,服务端答
- 无状态(需要 cookie / token)
- 1.1 支持长连接,2.0 多路复用
- 文本协议,可读性强
生产注意事项
- 不能服务端主动推送只能轮询、长轮询,效率低
- header 开销大尤其大量小请求,浪费严重
- 必须使用连接池原生 httpurlconnection 坑多,生产用 okhttp / resttemplate
- 超时三要素必须设置连接超时、读取超时、写入超时
- 重试要谨慎读接口可以重试,写接口(post/put)必须保证幂等
- https 必须使用明文传输极易被抓包篡改
4. websocket
特点
- 基于 tcp,在 http 握手升级而来
- 全双工:客户端 ↔ 服务端 随时发
- 一次握手,永久通道
- 数据帧很小,开销极低
- 服务端可以主动推送
生产注意事项
- 必须心跳代理、防火墙会断开空闲连接
- 集群环境要做会话共享多实例部署时,用 redis 广播 / stomp 消息队列
- 注意内存泄漏session 要及时清理,关闭连接必须移除集合
- 避免大文件传输不是设计用来传文件的
- 鉴权要在握手阶段做不要连接建立后再鉴权
三、它们之间的关系(一句话串起来)
- http 是跑在 tcp 上的应用协议
- websocket 也是跑在 tcp 上,先用 http 握手,再升级成双工通道
- tcp/udp 是底层传输,你要自己定义协议
- http/websocket 是现成协议,开箱即用
四、生产中怎么选择?(最实用)
- 业务接口、微服务调用 → http/https
- im、实时通知、大屏 → websocket
- 自定义长连接、网关、物联网 → tcp(netty)
- 直播、语音、实时游戏 → udp(可加可靠层)
- dns、心跳探测 → udp
到此这篇关于java 网络编程全解:tcp、udp、http、websocket的文章就介绍到这了,更多相关java 网络编程全解:tcp、udp、http、websocket内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论