WI
winking324/socketio-im-demo
IM Demo - 即时通讯系统演示
一个基于 Go + Socket.IO + Redis 的现代化即时通讯系统演示,支持 Web 浏览器、iOS/Android App 多平台接入。
功能特性
- ✅ 实时消息传输:基于 Socket.IO 实现低延迟实时通信
- ✅ 多消息类型:支持文字、文件、图片等多种消息类型
- ✅ 房间系统:支持多聊天室,用户可自由切换
- ✅ 文件传输:支持文件上传下载,最大 10MB
- ✅ 在线状态:实时显示用户在线状态
- ✅ 输入指示:显示用户正在输入状态
- ✅ 分布式架构:使用 Redis 支持多服务器实例部署
- ✅ 跨平台支持:Web 浏览器、移动 App 均可接入
- ✅ 优雅关闭:支持优雅关闭和重启
- ✅ 现代化 UI:响应式设计,支持桌面和移动端
技术栈
后端
- Go 1.21+:高性能服务器语言
- Gin:轻量级 Web 框架
- Socket.IO:实时双向通信
- Redis:分布式缓存和消息队列
- Logrus:结构化日志记录
前端
- HTML5/CSS3:现代化响应式设计
- JavaScript ES6+:客户端交互逻辑
- Socket.IO Client:WebSocket 客户端
项目结构
im-demo/
├── cmd/
│ └── server/
│ └── main.go # 服务器入口点
├── internal/
│ ├── config/
│ │ └── config.go # 配置管理
│ ├── handlers/
│ │ └── socketio.go # Socket.IO 处理器
│ ├── models/
│ │ └── message.go # 数据模型
│ └── services/
│ └── redis.go # Redis 服务
├── web/
│ ├── index.html # Web 客户端页面
│ └── client.js # 客户端 JavaScript
├── config.yaml # 配置文件
├── go.mod # Go 模块文件
└── README.md # 说明文档
快速开始
前置要求
- Go 1.21 或更高版本
- Redis 6.0 或更高版本
- 现代化浏览器(Chrome、Firefox、Safari、Edge)
安装步骤
-
克隆项目
git clone <your-repo-url> cd im-demo
-
安装依赖
go mod download
-
启动 Redis 服务器
# macOS (使用 Homebrew) brew install redis brew services start redis # Ubuntu/Debian sudo apt-get install redis-server sudo systemctl start redis # Docker docker run -d -p 6379:6379 redis:7-alpine
-
配置环境变量(可选)
export PORT=8080 export REDIS_ADDR=localhost:6379 export LOG_LEVEL=info
-
运行服务器
go run cmd/server/main.go
-
访问 Web 客户端
打开浏览器访问:
http://localhost
配置说明
配置文件 (config.yaml)
# 服务器配置
server:
port: 8080
host: localhost
env: development
# Redis 配置
redis:
addr: localhost:6379
password: ""
db: 0
# Socket.IO 配置
socketio:
cors_origins: "*"
ping_timeout: 60
ping_interval: 25
# 文件上传配置
upload:
max_file_size: 10485760 # 10MB
upload_dir: uploads/
# 日志配置
logging:
level: info
format: json环境变量
配置文件中的任何值都可以通过环境变量覆盖:
PORT: 服务器端口HOST: 服务器主机名ENV: 运行环境 (development/production)REDIS_ADDR: Redis 服务器地址REDIS_PASSWORD: Redis 密码REDIS_DB: Redis 数据库编号MAX_FILE_SIZE: 最大文件大小UPLOAD_DIR: 文件上传目录LOG_LEVEL: 日志级别
API 文档
Socket.IO 事件
客户端发送事件
| 事件名 | 数据格式 | 说明 |
|---|---|---|
join |
{userId, userName, avatar} |
用户加入系统 |
join_room |
{roomId, userId} |
加入聊天室 |
leave_room |
{roomId, userId} |
离开聊天室 |
message |
{type, content, sender, roomId, receiver} |
发送消息 |
file_upload |
{fileName, fileData, fileType, sender, roomId} |
上传文件 |
typing |
{userId, roomId} |
开始输入 |
stop_typing |
{userId, roomId} |
停止输入 |
服务器发送事件
| 事件名 | 数据格式 | 说明 |
|---|---|---|
joined |
{userId, userName, status} |
加入确认 |
message |
Message |
接收消息 |
user_status |
{userId, status} |
用户状态变更 |
room_joined |
{roomId, userId} |
房间加入确认 |
user_joined_room |
{userId, roomId} |
用户加入房间 |
user_left_room |
{userId, roomId} |
用户离开房间 |
typing |
{userId, roomId} |
用户正在输入 |
stop_typing |
{userId, roomId} |
用户停止输入 |
error |
{message} |
错误消息 |
HTTP API
文件上传
POST /api/upload
Content-Type: multipart/form-data
Form Data:
- file: 文件内容
获取房间成员
GET /api/rooms/:roomId/members
获取消息
GET /api/messages/:messageId
健康检查
GET /health
部署指南
生产环境部署
-
构建应用
go build -o im-server cmd/server/main.go
-
配置生产环境
server: port: 8080 host: 0.0.0.0 env: production redis: addr: your-redis-server:6379 password: your-redis-password logging: level: warn format: json
-
使用 systemd 管理服务
[Unit] Description=IM Demo Server After=network.target [Service] Type=simple User=www-data WorkingDirectory=/opt/im-demo ExecStart=/opt/im-demo/im-server Restart=always RestartSec=10 [Install] WantedBy=multi-user.target
-
Nginx 反向代理
server { listen 80; server_name your-domain.com; location / { proxy_pass http://localhost:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
Docker 部署
-
创建 Dockerfile
FROM golang:1.21-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN go build -o im-server cmd/server/main.go FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY --from=builder /app/im-server . COPY --from=builder /app/config.yaml . COPY --from=builder /app/web ./web EXPOSE 8080 CMD ["./im-server"]
-
Docker Compose
version: '3.8' services: im-server: build: . ports: - "8080:8080" depends_on: - redis environment: - REDIS_ADDR=redis:6379 - ENV=production redis: image: redis:7-alpine ports: - "6379:6379" volumes: - redis_data:/data volumes: redis_data:
移动端接入
iOS 接入示例
import SocketIO
class IMClient {
private var manager: SocketManager
private var socket: SocketIOClient
init() {
manager = SocketManager(socketURL: URL(string: "http://your-server:8080")!)
socket = manager.defaultSocket
socket.on(clientEvent: .connect) { data, ack in
print("Connected to server")
self.joinUser()
}
socket.on("message") { data, ack in
// Handle incoming message
if let messageData = data[0] as? [String: Any] {
self.handleMessage(messageData)
}
}
}
func connect() {
socket.connect()
}
func joinUser() {
socket.emit("join", [
"userId": "user123",
"userName": "iOS User",
"avatar": ""
])
}
func sendMessage(content: String, roomId: String) {
socket.emit("message", [
"type": "text",
"content": content,
"sender": "user123",
"roomId": roomId
])
}
}Android 接入示例
import io.socket.client.IO;
import io.socket.client.Socket;
import org.json.JSONObject;
public class IMClient {
private Socket socket;
public void connect() {
try {
socket = IO.socket("http://your-server:8080");
socket.on(Socket.EVENT_CONNECT, args -> {
System.out.println("Connected to server");
joinUser();
});
socket.on("message", args -> {
JSONObject message = (JSONObject) args[0];
handleMessage(message);
});
socket.connect();
} catch (Exception e) {
e.printStackTrace();
}
}
private void joinUser() {
try {
JSONObject userData = new JSONObject();
userData.put("userId", "user123");
userData.put("userName", "Android User");
userData.put("avatar", "");
socket.emit("join", userData);
} catch (Exception e) {
e.printStackTrace();
}
}
public void sendMessage(String content, String roomId) {
try {
JSONObject messageData = new JSONObject();
messageData.put("type", "text");
messageData.put("content", content);
messageData.put("sender", "user123");
messageData.put("roomId", roomId);
socket.emit("message", messageData);
} catch (Exception e) {
e.printStackTrace();
}
}
}性能优化
服务器端
-
连接池配置
// Redis 连接池 client := redis.NewClient(&redis.Options{ Addr: "localhost:6379", PoolSize: 10, MinIdleConns: 5, MaxRetries: 3, })
-
Socket.IO 优化
server := socketio.NewServer(&engineio.Options{ PingTimeout: 60 * time.Second, PingInterval: 25 * time.Second, Transports: []transport.Transport{websocket.Default}, })
-
消息压缩
// 在生产环境中启用消息压缩 server.SetCompressionLevel(6)
客户端
-
连接优化
const socket = io('/', { transports: ['websocket'], upgrade: false, rememberUpgrade: false, timeout: 20000, autoConnect: true, reconnection: true, reconnectionDelay: 1000, reconnectionDelayMax: 5000, reconnectionAttempts: 5 });
-
消息缓存
// 客户端消息缓存 class MessageCache { constructor(maxSize = 1000) { this.messages = new Map(); this.maxSize = maxSize; } add(message) { if (this.messages.size >= this.maxSize) { const firstKey = this.messages.keys().next().value; this.messages.delete(firstKey); } this.messages.set(message.id, message); } }
监控和日志
日志配置
logging:
level: info
format: json
file: /var/log/im-demo/app.log
max_size: 100MB
max_age: 30
max_backups: 10监控指标
- 连接数量
- 消息发送频率
- 错误率
- 响应时间
- 内存使用率
- Redis 连接状态
故障排除
常见问题
-
连接失败
- 检查 Redis 服务是否运行
- 确认防火墙设置
- 验证网络连接
-
文件上传失败
- 检查文件大小限制
- 确认上传目录权限
- 验证磁盘空间
-
消息丢失
- 检查 Redis 连接状态
- 确认网络稳定性
- 查看服务器日志
调试模式
# 开启调试日志
export LOG_LEVEL=debug
go run cmd/server/main.go贡献指南
- Fork 本项目
- 创建功能分支 (
git checkout -b feature/amazing-feature) - 提交更改 (
git commit -m 'Add amazing feature') - 推送到分支 (
git push origin feature/amazing-feature) - 创建 Pull Request
许可证
本项目采用 MIT 许可证 - 详见 LICENSE 文件
联系方式
- 项目主页:https://github.com/your-username/im-demo
- 问题反馈:https://github.com/your-username/im-demo/issues
- 邮箱:your-email@example.com
⭐ 如果这个项目对您有帮助,请给一个 Star!
On this page
Languages
Go36.0%HTML34.1%JavaScript29.0%Dockerfile0.9%
Contributors
MIT License
Created July 21, 2025
Updated September 19, 2025