本文目录导读:

我来详细讲解如何使用Socket实现TCP双向通信,包括客户端和服务器端的实现。
基础双向通信示例
服务器端 (Node.js)
const net = require('net');
// 创建TCP服务器
const server = net.createServer((socket) => {
console.log('客户端已连接');
// 接收客户端数据
socket.on('data', (data) => {
const message = data.toString();
console.log(`收到客户端消息: ${message}`);
// 回复客户端
socket.write(`服务器确认: 已收到 "${message}"`);
});
// 处理连接关闭
socket.on('end', () => {
console.log('客户端断开连接');
});
// 处理错误
socket.on('error', (err) => {
console.error('Socket错误:', err);
});
// 向客户端发送欢迎消息
socket.write('欢迎连接到服务器!');
});
// 监听端口
server.listen(8080, () => {
console.log('服务器启动在端口 8080');
});
客户端 (Node.js)
const net = require('net');
const readline = require('readline');
const client = new net.Socket();
// 创建命令行接口
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// 连接到服务器
client.connect(8080, 'localhost', () => {
console.log('已连接到服务器');
// 启动用户输入循环
console.log('请输入消息 (输入 "exit" 退出):');
startUserInput();
});
// 接收服务器数据
client.on('data', (data) => {
console.log(`\n服务器: ${data.toString()}`);
console.log('请输入消息:');
});
// 处理连接关闭
client.on('close', () => {
console.log('连接已关闭');
process.exit(0);
});
// 处理错误
client.on('error', (err) => {
console.error('错误:', err.message);
});
// 用户输入处理
function startUserInput() {
rl.on('line', (input) => {
if (input.toLowerCase() === 'exit') {
console.log('断开连接...');
client.end();
rl.close();
return;
}
// 发送消息到服务器
client.write(input);
});
}
增强版双向通信(带协议)
自定义协议定义
// 协议格式: [消息类型]:[内容]
// 消息类型: MSG, CMD, ERR, ACK
class MessageProtocol {
static encode(type, content) {
return `${type}:${content}`;
}
static decode(data) {
const parts = data.toString().split(':');
return {
type: parts[0],
content: parts.slice(1).join(':')
};
}
}
增强版服务器
const net = require('net');
const MessageProtocol = require('./protocol');
class TCPServer {
constructor(port) {
this.port = port;
this.clients = new Map();
this.server = null;
}
start() {
this.server = net.createServer((socket) => {
const clientId = `${socket.remoteAddress}:${socket.remotePort}`;
console.log(`新客户端连接: ${clientId}`);
// 存储客户端
this.clients.set(clientId, {
socket,
address: socket.remoteAddress,
port: socket.remotePort,
connectedAt: new Date()
});
// 发送欢迎消息
const welcome = MessageProtocol.encode('MSG', `欢迎 ${clientId}!`);
socket.write(welcome);
// 处理数据
socket.on('data', (data) => {
try {
const message = MessageProtocol.decode(data);
this.handleMessage(clientId, message);
} catch (err) {
const errorMsg = MessageProtocol.encode('ERR', '消息格式错误');
socket.write(errorMsg);
}
});
// 处理断开
socket.on('end', () => {
console.log(`客户端断开: ${clientId}`);
this.clients.delete(clientId);
this.broadcast(`用户 ${clientId} 已离线`);
});
// 处理错误
socket.on('error', (err) => {
console.error(`客户端错误 ${clientId}:`, err.message);
this.clients.delete(clientId);
});
});
this.server.listen(this.port, () => {
console.log(`TCP服务器启动在端口 ${this.port}`);
});
}
handleMessage(clientId, message) {
switch(message.type) {
case 'MSG':
console.log(`[${clientId}]: ${message.content}`);
// 广播消息给所有客户端
this.broadcast(`[${clientId}]: ${message.content}`, clientId);
break;
case 'CMD':
this.handleCommand(clientId, message.content);
break;
case 'ACK':
console.log(`确认消息: ${message.content}`);
break;
default:
const errorMsg = MessageProtocol.encode('ERR', '未知消息类型');
const client = this.clients.get(clientId);
if (client) client.socket.write(errorMsg);
}
}
handleCommand(clientId, command) {
const client = this.clients.get(clientId);
if (!client) return;
switch(command.trim().toUpperCase()) {
case 'HELP':
const helpMsg = MessageProtocol.encode('MSG', '可用命令: HELP, TIME, LIST, EXIT');
client.socket.write(helpMsg);
break;
case 'TIME':
const timeMsg = MessageProtocol.encode('MSG', `服务器时间: ${new Date().toLocaleString()}`);
client.socket.write(timeMsg);
break;
case 'LIST':
const userList = Array.from(this.clients.keys()).join(', ');
const listMsg = MessageProtocol.encode('MSG', `在线用户: ${userList}`);
client.socket.write(listMsg);
break;
case 'EXIT':
client.socket.end();
break;
default:
const errorMsg = MessageProtocol.encode('ERR', `未知命令: ${command}`);
client.socket.write(errorMsg);
}
}
broadcast(message, excludeClientId = null) {
this.clients.forEach((client, id) => {
if (id !== excludeClientId) {
const msg = MessageProtocol.encode('MSG', message);
client.socket.write(msg);
}
});
}
stop() {
this.clients.forEach((client) => {
client.socket.end();
});
this.server.close();
console.log('服务器已停止');
}
}
// 启动服务器
const server = new TCPServer(8080);
server.start();
增强版客户端
const net = require('net');
const readline = require('readline');
const MessageProtocol = require('./protocol');
class TCPClient {
constructor(host, port) {
this.host = host;
this.port = port;
this.socket = null;
this.username = '';
this.connected = false;
}
connect() {
this.socket = new net.Socket();
this.socket.connect(this.port, this.host, () => {
this.connected = true;
console.log(`已连接到 ${this.host}:${this.port}`);
this.startUserInput();
});
this.socket.on('data', (data) => {
this.handleMessage(data);
});
this.socket.on('close', () => {
this.connected = false;
console.log('连接已关闭');
process.exit(0);
});
this.socket.on('error', (err) => {
console.error('连接错误:', err.message);
this.connected = false;
});
}
handleMessage(data) {
try {
const message = MessageProtocol.decode(data);
switch(message.type) {
case 'MSG':
console.log(`\n${message.content}`);
break;
case 'CMD':
this.executeCommand(message.content);
break;
case 'ERR':
console.error(`\n错误: ${message.content}`);
break;
case 'ACK':
console.log(`\n确认: ${message.content}`);
break;
default:
console.log(`\n未知消息: ${data.toString()}`);
}
// 显示输入提示
if (this.connected) {
process.stdout.write('\n输入消息: ');
}
} catch (err) {
console.error('解析消息失败:', err.message);
}
}
startUserInput() {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// 获取用户名
this.getUsername(rl);
}
getUsername(rl) {
rl.question('请输入用户名: ', (username) => {
this.username = username.trim();
console.log(`你好, ${this.username}!`);
console.log('输入 /help 查看可用命令');
console.log('输入 /exit 退出');
process.stdout.write('输入消息: ');
rl.on('line', (input) => {
if (!input.trim()) return;
if (input.startsWith('/')) {
// 命令处理
const command = input.slice(1);
if (command.toLowerCase() === 'exit') {
console.log('断开连接...');
this.socket.end();
rl.close();
return;
}
// 发送命令到服务器
const cmdMsg = MessageProtocol.encode('CMD', command);
this.socket.write(cmdMsg);
} else {
// 普通消息
const msg = MessageProtocol.encode('MSG', input);
this.socket.write(msg);
}
process.stdout.write('输入消息: ');
});
});
}
executeCommand(command) {
switch(command.toUpperCase()) {
case 'CLEAR':
console.clear();
break;
default:
console.log(`未知客户端命令: ${command}`);
}
}
disconnect() {
if (this.socket) {
this.socket.end();
}
}
}
// 使用客户端
const client = new TCPClient('localhost', 8080);
client.connect();
// 优雅退出
process.on('SIGINT', () => {
console.log('\n正在退出...');
client.disconnect();
process.exit();
});
Python版双向通信
Python服务器
import socket
import threading
from datetime import datetime
class TCPServer:
def __init__(self, host='localhost', port=8080):
self.host = host
self.port = port
self.server_socket = None
self.clients = {}
def start(self):
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server_socket.bind((self.host, self.port))
self.server_socket.listen(5)
print(f"服务器启动在 {self.host}:{self.port}")
try:
while True:
client_socket, address = self.server_socket.accept()
print(f"新客户端连接: {address}")
# 为每个客户端创建线程
client_thread = threading.Thread(
target=self.handle_client,
args=(client_socket, address)
)
client_thread.start()
except KeyboardInterrupt:
print("\n服务器关闭中...")
finally:
self.stop()
def handle_client(self, client_socket, address):
client_id = f"{address[0]}:{address[1]}"
self.clients[client_id] = client_socket
# 发送欢迎消息
welcome = f"MSG:欢迎 {client_id} 连接到服务器!"
client_socket.send(welcome.encode())
while True:
try:
data = client_socket.recv(1024)
if not data:
break
message = data.decode()
print(f"[{client_id}]: {message}")
# 处理消息
response = self.process_message(client_id, message)
client_socket.send(response.encode())
except ConnectionResetError:
break
except Exception as e:
print(f"错误: {e}")
break
# 客户端断开
print(f"客户端断开: {client_id}")
del self.clients[client_id]
client_socket.close()
def process_message(self, client_id, message):
if message.startswith("CMD:"):
command = message[4:].strip().upper()
return self.handle_command(client_id, command)
elif message.startswith("MSG:"):
content = message[4:]
# 广播给其他客户端
self.broadcast(f"MSG:[{client_id}]: {content}", client_id)
return f"ACK:消息已发送"
else:
return f"MSG:收到: {message}"
def handle_command(self, client_id, command):
if command == "TIME":
return f"MSG:服务器时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
elif command == "LIST":
clients = ', '.join(self.clients.keys())
return f"MSG:在线用户: {clients}"
elif command == "HELP":
return "MSG:可用命令: TIME, LIST, HELP"
else:
return f"MSG:未知命令: {command}"
def broadcast(self, message, exclude_client=None):
for client_id, client_socket in self.clients.items():
if client_id != exclude_client:
try:
client_socket.send(message.encode())
except:
pass
def stop(self):
for client_socket in self.clients.values():
client_socket.close()
if self.server_socket:
self.server_socket.close()
print("服务器已停止")
# 启动服务器
if __name__ == "__main__":
server = TCPServer()
server.start()
Python客户端
import socket
import threading
import sys
class TCPClient:
def __init__(self, host='localhost', port=8080):
self.host = host
self.port = port
self.client_socket = None
self.connected = False
def connect(self):
try:
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client_socket.connect((self.host, self.port))
self.connected = True
print(f"已连接到 {self.host}:{self.port}")
# 启动接收消息线程
receive_thread = threading.Thread(target=self.receive_messages)
receive_thread.daemon = True
receive_thread.start()
# 处理用户输入
self.handle_input()
except Exception as e:
print(f"连接失败: {e}")
finally:
self.disconnect()
def receive_messages(self):
while self.connected:
try:
data = self.client_socket.recv(1024)
if not data:
break
message = data.decode()
if message.startswith("MSG:"):
print(f"\n{message[4:]}")
elif message.startswith("ACK:"):
print(f"\n确认: {message[4:]}")
elif message.startswith("ERR:"):
print(f"\n错误: {message[4:]}")
else:
print(f"\n服务器: {message}")
print("\n输入消息: ", end='', flush=True)
except ConnectionResetError:
break
except Exception as e:
print(f"\n接收错误: {e}")
break
self.connected = False
def handle_input(self):
print("输入 /help 查看命令")
print("输入 /exit 退出")
while self.connected:
try:
user_input = input("\n输入消息: ")
if not user_input.strip():
continue
if user_input.startswith('/'):
command = user_input[1:].strip()
if command.lower() == 'exit':
break
else:
self.client_socket.send(f"CMD:{command}".encode())
else:
self.client_socket.send(f"MSG:{user_input}".encode())
except KeyboardInterrupt:
break
except Exception as e:
print(f"输入错误: {e}")
break
def disconnect(self):
self.connected = False
if self.client_socket:
self.client_socket.close()
print("已断开连接")
# 启动客户端
if __name__ == "__main__":
client = TCPClient()
client.connect()
测试示例
多客户端测试脚本
// test_tcp.js
const net = require('net');
// 启动多个客户端测试
function createTestClient(name, port) {
const client = new net.Socket();
client.connect(port, 'localhost', () => {
console.log(`${name} 已连接`);
// 发送测试消息
client.write(`MSG:你好,我是 ${name}`);
// 延迟发送第二条消息
setTimeout(() => {
client.write(`MSG:${name} 的第二条消息`);
}, 2000);
// 延迟断开连接
setTimeout(() => {
client.end();
}, 5000);
});
client.on('data', (data) => {
console.log(`${name} 收到: ${data.toString()}`);
});
client.on('close', () => {
console.log(`${name} 连接关闭`);
});
return client;
}
// 创建3个测试客户端
createTestClient('客户端A', 8080);
createTestClient('客户端B', 8080);
createTestClient('客户端C', 8080);
关键特性和最佳实践
- 双向通信: 客户端和服务器都可以主动发送消息
- 消息协议: 使用自定义协议区分不同类型的消息
- 并发处理: 支持多客户端同时连接
- 错误处理: 完善的异常处理和连接管理
- 用户界面: 提供命令行交互界面
最佳实践
- 消息缓冲区: 处理大消息时需要缓冲区
- 心跳机制: 定期发送心跳包检测连接状态
- 重连机制: 实现自动重连逻辑
- 消息队列: 使用队列管理待发送消息
- 流量控制: 实现背压机制防止数据溢出
这些示例提供了完整的TCP双向通信实现,你可以根据自己的需求进行修改和扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播