HarmonyOS PC开发中Socket TCP编程:传输层网络通信
HarmonyOS PC开发中Socket TCP编程:传输层网络通信
深入传输层,掌握TCP Socket让你的应用拥有更底层的网络控制能力
一、背景与动机:为什么需要TCP Socket?
HTTP、WebSocket这些应用层协议已经很好用了,为什么还要学习TCP Socket?
性能极致要求:HTTP有大量头信息,WebSocket有帧封装开销。对于追求极致性能的场景(如游戏、实时音视频),直接使用TCP可以减少开销。
自定义协议:某些场景需要自定义二进制协议,HTTP/WebSocket无法满足。比如物联网设备的专有协议、金融交易系统的定长报文。
长连接管理:TCP提供更细粒度的连接控制,可以实现连接池、多路复用等高级特性。
学习底层原理:理解TCP Socket有助于深入理解网络编程,遇到问题时能从底层分析。
鸿蒙系统提供了@ohos.net.socket模块,支持TCP和UDP两种Socket类型。本文聚焦TCP,下一篇讲UDP。
二、核心原理:TCP连接与数据传输
2.1 TCP三次握手与四次挥手
2.2 TCP特性与应用场景
| TCP特性 | 说明 | 应用场景 |
|---|---|---|
| 面向连接 | 通信前需建立连接 | 需要可靠传输的场景 |
| 可靠传输 | 通过确认、重传保证数据到达 | 文件传输、消息发送 |
| 有序传输 | 数据按发送顺序到达 | 流式数据处理 |
| 流量控制 | 滑动窗口机制,避免接收方溢出 | 大数据传输 |
| 拥塞控制 | 慢启动、拥塞避免,公平使用网络 | 公网通信 |
2.3 鸿蒙TCP Socket API
import socket from '@ohos.net.socket';
// 创建TCP Socket
let tcpSocket = socket.constructTCPSocketServerInstance(); // 服务端
let tcpClient = socket.constructTCPSocketInstance(); // 客户端
// 客户端连接
await tcpClient.connect({
address: {
address: '192.168.1.100',
port: 8080,
family: 1 // IPv4
},
timeout: 60000
});
// 发送数据
await tcpClient.send({
data: 'Hello Server'
});
// 接收数据
tcpClient.on('message', (value) => {
console.info('收到数据:', value.message);
});
// 关闭连接
await tcpClient.close();
三、代码实战:三种典型场景
场景一:TCP客户端实现
实现一个完整的TCP客户端,连接服务器并进行数据交互。
import socket from '@ohos.net.socket';
import { BusinessError } from '@ohos.base';
// TCP客户端配置
interface TCPClientConfig {
host: string;
port: number;
timeout?: number;
reconnect?: boolean;
reconnectInterval?: number;
}
// TCP客户端
class TCPClient {
private socket: socket.TCPSocket | null = null;
private config: TCPClientConfig;
private isConnected: boolean = false;
// 接收数据缓冲区
private receiveBuffer: ArrayBuffer[] = [];
// 回调
private onMessage: ((data: ArrayBuffer) => void) | null = null;
private onConnectionChange: ((connected: boolean) => void) | null = null;
private onError: ((error: BusinessError) => void) | null = null;
constructor(config: TCPClientConfig) {
this.config = {
timeout: 60000,
reconnect: false,
reconnectInterval: 5000,
...config
};
}
// 连接服务器
async connect(): Promise<boolean> {
if (this.isConnected) {
console.warn('已连接');
return true;
}
// 创建Socket
this.socket = socket.constructTCPSocketInstance();
try {
// 绑定本地地址(可选)
await this.socket.bind({
address: '0.0.0.0', // 自动选择
port: 0, // 自动分配端口
family: 1 // IPv4
});
// 连接服务器
await this.socket.connect({
address: {
address: this.config.host,
port: this.config.port,
family: 1
},
timeout: this.config.timeout
});
this.isConnected = true;
// 设置事件监听
this.setupListeners();
// 通知连接成功
this.onConnectionChange?.(true);
console.info(`TCP连接成功: ${this.config.host}:${this.config.port}`);
return true;
} catch (error) {
let e = error as BusinessError;
console.error('TCP连接失败:', e.message);
this.onError?.(e);
// 尝试重连
if (this.config.reconnect) {
this.scheduleReconnect();
}
return false;
}
}
// 设置事件监听
private setupListeners(): void {
if (!this.socket) return;
// 接收数据
this.socket.on('message', (value: socket.SocketMessageInfo) => {
// 数据到达
let data = value.message;
console.debug(`收到数据: ${data.byteLength} 字节`);
// 通知上层
this.onMessage?.(data);
});
// 连接关闭
this.socket.on('close', () => {
console.info('连接已关闭');
this.isConnected = false;
this.onConnectionChange?.(false);
// 尝试重连
if (this.config.reconnect) {
this.scheduleReconnect();
}
});
// 错误
this.socket.on('error', (err: BusinessError) => {
console.error('Socket错误:', err.message);
this.isConnected = false;
this.onError?.(err);
});
}
// 发送数据
async send(data: string | ArrayBuffer): Promise<boolean> {
if (!this.socket || !this.isConnected) {
console.error('未连接,无法发送');
return false;
}
try {
let sendData: socket.TCPSendOptions;
if (typeof data === 'string') {
// 字符串转ArrayBuffer
let encoder = new TextEncoder();
let buffer = encoder.encode(data);
sendData = { data: buffer.buffer };
} else {
sendData = { data: data };
}
await this.socket.send(sendData);
console.debug(`发送数据: ${sendData.data.byteLength} 字节`);
return true;
} catch (error) {
console.error('发送失败:', error);
return false;
}
}
// 发送二进制数据(指定偏移和长度)
async sendBinary(data: ArrayBuffer, offset: number = 0, length?: number): Promise<boolean> {
if (!this.socket || !this.isConnected) {
return false;
}
try {
let actualLength = length || data.byteLength - offset;
// 创建视图发送部分数据
let view = new Uint8Array(data, offset, actualLength);
await this.socket.send({
data: view.buffer
});
return true;
} catch (error) {
console.error('发送二进制数据失败:', error);
return false;
}
}
// 获取本地地址
async getLocalAddress(): Promise<socket.NetAddress | null> {
if (!this.socket) return null;
try {
let info = await this.socket.getState();
return {
address: info.localAddress,
port: info.localPort,
family: 1
};
} catch (error) {
return null;
}
}
// 获取远程地址
async getRemoteAddress(): Promise<socket.NetAddress | null> {
if (!this.socket) return null;
try {
let info = await this.socket.getState();
return {
address: info.remoteAddress,
port: info.remotePort,
family: 1
};
} catch (error) {
return null;
}
}
// 关闭连接
async close(): Promise<void> {
if (this.socket) {
try {
await this.socket.close();
console.info('连接已关闭');
} catch (error) {
console.error('关闭连接失败:', error);
}
this.socket = null;
this.isConnected = false;
}
}
// 调度重连
private scheduleReconnect(): void {
setTimeout(() => {
console.info('尝试重连...');
this.connect();
}, this.config.reconnectInterval);
}
// 设置回调
setOnMessage(callback: (data: ArrayBuffer) => void): void {
this.onMessage = callback;
}
setOnConnectionChange(callback: (connected: boolean) => void): void {
this.onConnectionChange = callback;
}
setOnError(callback: (error: BusinessError) => void): void {
this.onError = callback;
}
// 获取连接状态
isConnected_(): boolean {
return this.isConnected;
}
}
// 使用示例:TCP客户端页面
@Entry
@Component
struct TCPClientPage {
@State connectionStatus: string = '未连接';
@State receivedData: string = '';
@State sentCount: number = 0;
@State receivedCount: number = 0;
private tcpClient: TCPClient | null = null;
private dataBuffer: string = '';
async aboutToAppear() {
this.tcpClient = new TCPClient({
host: '192.168.1.100',
port: 8888,
reconnect: true
});
// 设置回调
this.tcpClient.setOnConnectionChange((connected) => {
this.connectionStatus = connected ? '已连接' : '未连接';
});
this.tcpClient.setOnMessage((data) => {
// 解析数据
let decoder = new TextDecoder();
let text = decoder.decode(data);
this.dataBuffer += text;
this.receivedCount += data.byteLength;
// 显示最近的数据
if (this.dataBuffer.length > 1000) {
this.dataBuffer = this.dataBuffer.slice(-1000);
}
this.receivedData = this.dataBuffer;
});
// 连接服务器
await this.tcpClient.connect();
}
async aboutToDisappear() {
await this.tcpClient?.close();
}
// 发送测试数据
async sendTestData() {
let message = `Test message ${Date.now()}\n`;
let success = await this.tcpClient?.send(message);
if (success) {
this.sentCount += message.length;
}
}
build() {
Column() {
// 连接状态
Row() {
Text('连接状态:')
.fontSize(16)
Text(this.connectionStatus)
.fontSize(16)
.fontColor(this.connectionStatus === '已连接' ? '#7ED321' : '#D0021B')
.margin({ left: 10 })
}
.width('100%')
.padding(15)
// 统计信息
Row() {
Text(`发送: ${this.sentCount} 字节`)
.fontSize(14)
.layoutWeight(1)
Text(`接收: ${this.receivedCount} 字节`)
.fontSize(14)
.layoutWeight(1)
}
.width('100%')
.padding(10)
// 接收数据区域
Column() {
Text('接收数据:')
.fontSize(14)
.width('100%')
Scroll() {
Text(this.receivedData || '暂无数据')
.fontSize(12)
.fontFamily('monospace')
}
.width('100%')
.height(200)
.backgroundColor('#F5F5F5')
.padding(10)
}
.width('100%')
.padding(10)
// 操作按钮
Row() {
Button('发送测试数据')
.onClick(() => this.sendTestData())
.layoutWeight(1)
Button('清空数据')
.onClick(() => {
this.dataBuffer = '';
this.receivedData = '';
})
.layoutWeight(1)
.margin({ left: 10 })
}
.width('100%')
.padding(10)
}
.width('100%')
.height('100%')
}
}
场景二:TCP服务端实现
实现一个TCP服务器,监听端口并处理客户端连接。
import socket from '@ohos.net.socket';
import { BusinessError } from '@ohos.base';
// 客户端连接信息
interface ClientConnection {
id: string;
socket: socket.TCPSocket;
remoteAddress: string;
remotePort: number;
connectTime: number;
}
// TCP服务端配置
interface TCPServerConfig {
port: number;
host?: string;
backlog?: number; // 等待连接队列长度
}
// TCP服务端
class TCPServer {
private serverSocket: socket.TCPSocketServer | null = null;
private config: TCPServerConfig;
private isListening: boolean = false;
// 客户端连接管理
private clients: Map<string, ClientConnection> = new Map();
private clientCounter: number = 0;
// 回调
private onClientConnect: ((client: ClientConnection) => void) | null = null;
private onClientDisconnect: ((clientId: string) => void) | null = null;
private onMessage: ((clientId: string, data: ArrayBuffer) => void) | null = null;
constructor(config: TCPServerConfig) {
this.config = {
host: '0.0.0.0',
backlog: 10,
...config
};
}
// 启动服务器
async start(): Promise<boolean> {
if (this.isListening) {
console.warn('服务器已启动');
return true;
}
// 创建服务端Socket
this.serverSocket = socket.constructTCPSocketServerInstance();
try {
// 绑定地址和端口
await this.serverSocket.bind({
address: this.config.host,
port: this.config.port,
family: 1
});
// 开始监听
await this.serverSocket.listen({
backlog: this.config.backlog
});
this.isListening = true;
// 设置连接监听
this.setupListeners();
console.info(`TCP服务器启动: ${this.config.host}:${this.config.port}`);
return true;
} catch (error) {
console.error('启动服务器失败:', error);
return false;
}
}
// 设置监听
private setupListeners(): void {
if (!this.serverSocket) return;
// 监听客户端连接
this.serverSocket.on('connect', (client: socket.TCPSocket) => {
this.handleNewConnection(client);
});
}
// 处理新连接
private async handleNewConnection(client: socket.TCPSocket): Promise<void> {
try {
// 获取客户端信息
let state = await client.getState();
// 生成客户端ID
let clientId = `client_${++this.clientCounter}`;
let connection: ClientConnection = {
id: clientId,
socket: client,
remoteAddress: state.remoteAddress,
remotePort: state.remotePort,
connectTime: Date.now()
};
// 保存连接
this.clients.set(clientId, connection);
console.info(`新客户端连接: ${clientId} from ${connection.remoteAddress}:${connection.remotePort}`);
// 设置客户端消息监听
client.on('message', (value: socket.SocketMessageInfo) => {
this.onMessage?.(clientId, value.message);
});
// 设置客户端断开监听
client.on('close', () => {
console.info(`客户端断开: ${clientId}`);
this.clients.delete(clientId);
this.onClientDisconnect?.(clientId);
});
client.on('error', (err: BusinessError) => {
console.error(`客户端错误 ${clientId}:`, err.message);
this.clients.delete(clientId);
});
// 通知新连接
this.onClientConnect?.(connection);
} catch (error) {
console.error('处理新连接失败:', error);
}
}
// 向指定客户端发送数据
async sendToClient(clientId: string, data: string | ArrayBuffer): Promise<boolean> {
let client = this.clients.get(clientId);
if (!client) {
console.error('客户端不存在:', clientId);
return false;
}
try {
let sendData: socket.TCPSendOptions;
if (typeof data === 'string') {
let encoder = new TextEncoder();
sendData = { data: encoder.encode(data).buffer };
} else {
sendData = { data: data };
}
await client.socket.send(sendData);
return true;
} catch (error) {
console.error('发送失败:', error);
return false;
}
}
// 广播数据给所有客户端
async broadcast(data: string | ArrayBuffer): Promise<void> {
let promises: Promise<boolean>[] = [];
this.clients.forEach((client, clientId) => {
promises.push(this.sendToClient(clientId, data));
});
await Promise.all(promises);
}
// 断开指定客户端
async disconnectClient(clientId: string): Promise<void> {
let client = this.clients.get(clientId);
if (client) {
try {
await client.socket.close();
} catch (error) {
// 忽略
}
this.clients.delete(clientId);
}
}
// 停止服务器
async stop(): Promise<void> {
// 断开所有客户端
for (let [clientId, client] of this.clients) {
try {
await client.socket.close();
} catch (error) {
// 忽略
}
}
this.clients.clear();
// 关闭服务端Socket
if (this.serverSocket) {
try {
await this.serverSocket.close();
} catch (error) {
// 忽略
}
this.serverSocket = null;
}
this.isListening = false;
console.info('服务器已停止');
}
// 获取所有客户端
getConnectedClients(): ClientConnection[] {
return Array.from(this.clients.values());
}
// 获取客户端数量
getClientCount(): number {
return this.clients.size;
}
// 设置回调
setOnClientConnect(callback: (client: ClientConnection) => void): void {
this.onClientConnect = callback;
}
setOnClientDisconnect(callback: (clientId: string) => void): void {
this.onClientDisconnect = callback;
}
setOnMessage(callback: (clientId: string, data: ArrayBuffer) => void): void {
this.onMessage = callback;
}
// 获取监听状态
isListening_(): boolean {
return this.isListening;
}
}
// TCP服务端页面
@Entry
@Component
struct TCPServerPage {
@State serverStatus: string = '未启动';
@State clientCount: number = 0;
@State clients: ClientConnection[] = [];
@State logs: string[] = [];
private tcpServer: TCPServer | null = null;
async aboutToAppear() {
this.tcpServer = new TCPServer({
port: 8888
});
// 设置回调
this.tcpServer.setOnClientConnect((client) => {
this.clients = this.tcpServer?.getConnectedClients() || [];
this.clientCount = this.clients.length;
this.addLog(`客户端连接: ${client.remoteAddress}:${client.remotePort}`);
});
this.tcpServer.setOnClientDisconnect((clientId) => {
this.clients = this.tcpServer?.getConnectedClients() || [];
this.clientCount = this.clients.length;
this.addLog(`客户端断开: ${clientId}`);
});
this.tcpServer.setOnMessage((clientId, data) => {
let decoder = new TextDecoder();
let text = decoder.decode(data);
this.addLog(`收到消息 [${clientId}]: ${text.substring(0, 50)}`);
});
}
async aboutToDisappear() {
await this.tcpServer?.stop();
}
// 启动服务器
async startServer() {
let success = await this.tcpServer?.start();
this.serverStatus = success ? '运行中' : '启动失败';
this.addLog(`服务器${success ? '启动成功' : '启动失败'}`);
}
// 停止服务器
async stopServer() {
await this.tcpServer?.stop();
this.serverStatus = '已停止';
this.addLog('服务器已停止');
}
// 广播消息
async broadcastMessage() {
let message = `Server broadcast at ${Date.now()}\n`;
await this.tcpServer?.broadcast(message);
this.addLog(`广播消息: ${message.trim()}`);
}
// 添加日志
private addLog(log: string) {
let time = new Date().toLocaleTimeString();
this.logs.unshift(`[${time}] ${log}`);
if (this.logs.length > 50) {
this.logs.pop();
}
}
build() {
Column() {
// 服务器状态
Row() {
Text('服务器状态:')
.fontSize(16)
Text(this.serverStatus)
.fontSize(16)
.fontColor(this.serverStatus === '运行中' ? '#7ED321' : '#666')
.margin({ left: 10 })
Blank().layoutWeight(1)
Text(`客户端: ${this.clientCount}`)
.fontSize(16)
}
.width('100%')
.padding(15)
// 控制按钮
Row() {
Button('启动服务器')
.onClick(() => this.startServer())
.enabled(this.serverStatus !== '运行中')
.layoutWeight(1)
Button('停止服务器')
.onClick(() => this.stopServer())
.enabled(this.serverStatus === '运行中')
.layoutWeight(1)
.margin({ left: 10 })
Button('广播消息')
.onClick(() => this.broadcastMessage())
.enabled(this.serverStatus === '运行中')
.layoutWeight(1)
.margin({ left: 10 })
}
.width('100%')
.padding(10)
// 客户端列表
if (this.clients.length > 0) {
Column() {
Text('已连接客户端:')
.fontSize(14)
.width('100%')
ForEach(this.clients, (client: ClientConnection) => {
Row() {
Text(client.id)
.fontSize(12)
.layoutWeight(1)
Text(`${client.remoteAddress}:${client.remotePort}`)
.fontSize(12)
.fontColor('#666')
}
.width('100%')
.padding(5)
}, (client: ClientConnection) => client.id)
}
.width('100%')
.padding(10)
}
// 日志区域
Column() {
Text('服务器日志:')
.fontSize(14)
.width('100%')
List() {
ForEach(this.logs, (log: string, index: number) => {
ListItem() {
Text(log)
.fontSize(12)
.fontFamily('monospace')
}
})
}
.width('100%')
.height(200)
.backgroundColor('#F5F5F5')
}
.width('100%')
.padding(10)
.layoutWeight(1)
}
.width('100%')
.height('100%')
}
}
场景三:自定义协议实现
实现一个基于TCP的自定义二进制协议,包含消息头和消息体。
import socket from '@ohos.net.socket';
// 自定义协议消息头(固定16字节)
// | 魔数(4B) | 版本(1B) | 类型(1B) | 长度(4B) | 序列号(4B) | 保留(2B) |
// 消息类型
enum MessageType {
HEARTBEAT = 0x01,
DATA = 0x02,
ACK = 0x03,
ERROR = 0x04
}
// 协议常量
const MAGIC_NUMBER = 0x484D5350; // 'HMSP'
const PROTOCOL_VERSION = 0x01;
const HEADER_SIZE = 16;
// 消息结构
interface ProtocolMessage {
type: MessageType;
sequence: number;
payload: ArrayBuffer;
}
// 协议编解码器
class ProtocolCodec {
private sequence: number = 0;
// 编码消息
encode(message: ProtocolMessage): ArrayBuffer {
// 计算总长度
let totalLength = HEADER_SIZE + message.payload.byteLength;
let buffer = new ArrayBuffer(totalLength);
let view = new DataView(buffer);
// 写入消息头
let offset = 0;
// 魔数 (4字节)
view.setUint32(offset, MAGIC_NUMBER, false);
offset += 4;
// 版本 (1字节)
view.setUint8(offset, PROTOCOL_VERSION);
offset += 1;
// 消息类型 (1字节)
view.setUint8(offset, message.type);
offset += 1;
// 负载长度 (4字节)
view.setUint32(offset, message.payload.byteLength, false);
offset += 4;
// 序列号 (4字节)
view.setUint32(offset, message.sequence, false);
offset += 4;
// 保留字段 (2字节)
view.setUint16(offset, 0, false);
offset += 2;
// 写入消息体
let payloadView = new Uint8Array(message.payload);
let bodyView = new Uint8Array(buffer, HEADER_SIZE);
for (let i = 0; i < payloadView.length; i++) {
bodyView[i] = payloadView[i];
}
return buffer;
}
// 解码消息
decode(buffer: ArrayBuffer): ProtocolMessage | null {
if (buffer.byteLength < HEADER_SIZE) {
console.error('数据长度不足');
return null;
}
let view = new DataView(buffer);
let offset = 0;
// 读取魔数
let magic = view.getUint32(offset, false);
offset += 4;
if (magic !== MAGIC_NUMBER) {
console.error('魔数不匹配');
return null;
}
// 读取版本
let version = view.getUint8(offset);
offset += 1;
if (version !== PROTOCOL_VERSION) {
console.error('协议版本不匹配');
return null;
}
// 读取消息类型
let type = view.getUint8(offset) as MessageType;
offset += 1;
// 读取负载长度
let payloadLength = view.getUint32(offset, false);
offset += 4;
// 读取序列号
let sequence = view.getUint32(offset, false);
offset += 4;
// 跳过保留字段
offset += 2;
// 读取负载
let payload = new ArrayBuffer(payloadLength);
if (payloadLength > 0 && buffer.byteLength >= HEADER_SIZE + payloadLength) {
let payloadView = new Uint8Array(payload);
let bodyView = new Uint8Array(buffer, HEADER_SIZE, payloadLength);
for (let i = 0; i < payloadLength; i++) {
payloadView[i] = bodyView[i];
}
}
return {
type: type,
sequence: sequence,
payload: payload
};
}
// 创建心跳消息
createHeartbeat(): ProtocolMessage {
return {
type: MessageType.HEARTBEAT,
sequence: ++this.sequence,
payload: new ArrayBuffer(0)
};
}
// 创建数据消息
createDataMessage(data: string | ArrayBuffer): ProtocolMessage {
let payload: ArrayBuffer;
if (typeof data === 'string') {
let encoder = new TextEncoder();
payload = encoder.encode(data).buffer;
} else {
payload = data;
}
return {
type: MessageType.DATA,
sequence: ++this.sequence,
payload: payload
};
}
// 创建ACK消息
createAck(sequence: number): ProtocolMessage {
let payload = new ArrayBuffer(4);
let view = new DataView(payload);
view.setUint32(0, sequence, false);
return {
type: MessageType.ACK,
sequence: ++this.sequence,
payload: payload
};
}
}
// 基于自定义协议的TCP客户端
class ProtocolTCPClient extends TCPClient {
private codec: ProtocolCodec = new ProtocolCodec();
private pendingMessages: Map<number, { resolve: Function; reject: Function; timer: number }> = new Map();
private ackTimeout: number = 5000;
// 发送数据消息(等待ACK)
async sendDataWithAck(data: string | ArrayBuffer): Promise<boolean> {
let message = this.codec.createDataMessage(data);
let encoded = this.codec.encode(message);
// 设置ACK等待
return new Promise(async (resolve, reject) => {
let timer = setTimeout(() => {
this.pendingMessages.delete(message.sequence);
reject(new Error('ACK超时'));
}, this.ackTimeout);
this.pendingMessages.set(message.sequence, {
resolve: resolve,
reject: reject,
timer: timer
});
// 发送消息
let success = await this.send(encoded);
if (!success) {
clearTimeout(timer);
this.pendingMessages.delete(message.sequence);
reject(new Error('发送失败'));
}
});
}
// 发送心跳
async sendHeartbeat(): Promise<boolean> {
let message = this.codec.createHeartbeat();
let encoded = this.codec.encode(message);
return await this.send(encoded);
}
// 处理接收数据
protected handleReceivedData(data: ArrayBuffer): void {
let message = this.codec.decode(data);
if (!message) {
console.error('消息解码失败');
return;
}
switch (message.type) {
case MessageType.ACK:
// 处理ACK
let view = new DataView(message.payload);
let ackedSequence = view.getUint32(0, false);
let pending = this.pendingMessages.get(ackedSequence);
if (pending) {
clearTimeout(pending.timer);
this.pendingMessages.delete(ackedSequence);
pending.resolve(true);
}
break;
case MessageType.DATA:
// 处理数据消息
let decoder = new TextDecoder();
let text = decoder.decode(message.payload);
console.info(`收到数据: ${text}`);
// 发送ACK
this.sendAck(message.sequence);
break;
case MessageType.HEARTBEAT:
// 心跳响应
console.debug('收到心跳');
break;
}
}
// 发送ACK
private async sendAck(sequence: number): Promise<void> {
let message = this.codec.createAck(sequence);
let encoded = this.codec.encode(message);
await this.send(encoded);
}
}
四、踩坑与注意事项
坑点一:数据粘包问题
TCP是流式协议,多次发送的数据可能被合并接收。
// ❌ 错误:假设一次发送对应一次接收
tcpClient.on('message', (data) => {
// 可能收到多个消息的合并数据
let message = parseMessage(data); // 解析失败!
});
// ✅ 正确:使用长度前缀或分隔符
// 方案1:长度前缀
function encodeWithLength(data: ArrayBuffer): ArrayBuffer {
let buffer = new ArrayBuffer(4 + data.byteLength);
let view = new DataView(buffer);
view.setUint32(0, data.byteLength, false); // 写入长度
let dataView = new Uint8Array(buffer, 4);
let sourceView = new Uint8Array(data);
for (let i = 0; i < sourceView.length; i++) {
dataView[i] = sourceView[i];
}
return buffer;
}
// 方案2:分隔符
function encodeWithDelimiter(data: string): string {
return data + '\n'; // 使用换行符分隔
}
坑点二:未设置超时导致无限等待
连接或发送操作可能永久阻塞。
// ❌ 错误:未设置超时
await tcpClient.connect({
address: { address: '192.168.1.100', port: 8888, family: 1 }
// 没有timeout,可能永久等待
});
// ✅ 正确:设置合理超时
await tcpClient.connect({
address: { address: '192.168.1.100', port: 8888, family: 1 },
timeout: 30000 // 30秒超时
});
坑点三:资源未释放
Socket对象未正确关闭,导致资源泄漏。
// ❌ 错误:忘记关闭
async function badExample() {
let tcp = socket.constructTCPSocketInstance();
await tcp.connect(...);
// 使用后忘记关闭
}
// ✅ 正确:确保关闭
async function goodExample() {
let tcp = socket.constructTCPSocketInstance();
try {
await tcp.connect(...);
// 使用...
} finally {
try {
await tcp.close();
} catch (error) {
// 忽略关闭错误
}
}
}
五、HarmonyOS 6适配指南
5.1 新增配置选项
HarmonyOS 6提供了更丰富的Socket配置。
import socket from '@ohos.net.socket';
let tcp = socket.constructTCPSocketInstance();
// HarmonyOS 6: 高级配置
await tcp.connect({
address: {
address: '192.168.1.100',
port: 8888,
family: 1
},
timeout: 30000,
// 新增:TCP选项
tcpOptions: {
// 是否启用TCP_NODELAY(禁用Nagle算法)
noDelay: true,
// 保活选项
keepAlive: true,
keepIdle: 7200, // 空闲多久开始探测
keepInterval: 75, // 探测间隔
keepCount: 9, // 探测次数
// 接收缓冲区大小
receiveBufferSize: 65536,
// 发送缓冲区大小
sendBufferSize: 65536
}
});
5.2 异步回调优化
HarmonyOS 6优化了异步回调机制。
// 使用Promise风格
try {
let state = await tcp.getState();
console.info('本地地址:', state.localAddress);
console.info('远程地址:', state.remoteAddress);
} catch (error) {
console.error('获取状态失败:', error);
}
六、总结
TCP Socket是网络编程的基础,掌握它对深入理解网络通信至关重要。本文从三个场景展开:
TCP客户端:主动连接服务器,发送和接收数据。注意连接状态管理、数据缓冲、异常处理。
TCP服务端:监听端口,接受客户端连接。需要管理多个客户端连接,处理并发访问。
自定义协议:在TCP之上构建应用协议。设计消息格式、实现编解码、处理粘包问题。
三个常见坑点:数据粘包、未设置超时、资源未释放。遇到TCP问题时,先排查这三个方面。
HarmonyOS 6提供了更丰富的TCP配置选项,如TCP_NODELAY、Keep-Alive等,可以针对不同场景优化性能。
下一篇文章,我们将探索UDP Socket编程,了解无连接数据传输的特点!
更多推荐

所有评论(0)