| 庫 | 評價 |
|---|---|
| Boost.Asio / ACE | 功能強但過於龐大,編譯依賴重 |
| libevent | 成熟穩定,但 API 風格較 C 風格 |
| libev | 輕量快速,但功能相對簡單 |
| libuv | Node.js 底層引擎,跨平台、異步 IO 完備、活躍維護 |
uv_tcp_t + uv_loop_t,管理客戶端映射 map<int, clientdata*>newconnect、server_recvcb、client_recvcbuv_close 回調中釋放 clientdataclass TCPServer {
public:
TCPServer(uv_loop_t* loop = uv_default_loop());
~TCPServer();
bool Start(const char* ip, int port); // IPv4
bool Start6(const char* ip, int port); // IPv6
void close();
int send(int clientid, const char* data, size_t len);
void setnewconnectcb(newconnect cb);
void setrecvcb(int clientid, server_recvcb cb);
const char* GetLastErrMsg() const;
private:
uv_tcp_t server_;
map clients_list_;
uv_mutex_t mutex_handle_;
uv_loop_t* loop_;
newconnect newconcb_;
bool isinit_;
// 靜態回調:acceptConnection, AfterServerRecv, AfterSend, onAllocBuffer...
};
class TCPClient {
public:
TCPClient(uv_loop_t* loop = uv_default_loop());
~TCPClient();
bool connect(const char* ip, int port); // 阻塞直到連接完成
bool connect6(const char* ip, int port);
int send(const char* data, size_t len);
void setrecvcb(client_recvcb cb, void* userdata);
void close();
bool setNoDelay(bool enable);
bool setKeepAlive(int enable, unsigned int delay);
private:
uv_tcp_t client_;
uv_loop_t* loop_;
uv_thread_t connect_threadhanlde_; // 連接線程
uv_mutex_t write_mutex_handle_; // 發送串行化
enum { CONNECT_TIMEOUT, CONNECT_FINISH, CONNECT_ERROR, CONNECT_DIS };
int connectstatus_;
client_recvcb recvcb_;
void* userdata_;
// 靜態回調:AfterConnect, AfterClientRecv, AfterSend, onAllocBuffer...
};
void TCPServer::acceptConnection(uv_stream_t* server, int status) {
TCPServer* tcpsock = (TCPServer*)server->data;
int clientid = tcpsock->GetAvailaClientID(); // 原子遞增
clientdata* cdata = new clientdata(clientid);
cdata->tcp_server = tcpsock;
uv_tcp_init(tcpsock->loop_, cdata->client_handle);
uv_accept((uv_stream_t*)&tcpsock->server_, (uv_stream_t*)cdata->client_handle);
tcpsock->clients_list_[clientid] = cdata;
if (tcpsock->newconcb_) tcpsock->newconcb_(clientid);
uv_read_start((uv_stream_t*)cdata->client_handle, onAllocBuffer, AfterServerRecv);
}
onAllocBuffer 直接返回預分配的 readbuffer/writebuffer (1MB)realloc 擴容,**生命週期由發送者控制**,直到 AfterSend 回調write_mutex_handle_ 串行化,避免併發寫亂序bool TCPClient::connect(const char* ip, int port) {
close(); init();
connectip_ = ip; connectport_ = port;
uv_thread_create(&connect_threadhanlde_, ConnectThread, this);
while (connectstatus_ == CONNECT_DIS) Sleep(100); // 等待連接完成
return connectstatus_ == CONNECT_FINISH;
}
void TCPClient::ConnectThread(void* arg) {
TCPClient* pclient = (TCPClient*)arg;
sockaddr_in bind_addr;
uv_ip4_addr(pclient->connectip_.c_str(), pclient->connectport_, &bind_addr);
uv_tcp_connect(&pclient->connect_req_, &pclient->client_, (sockaddr*)&bind_addr, AfterConnect);
pclient->run(); // 在連接線程運行事件循環
}
**設計亮點**:連接過程在獨立線程,主線程可做其他事;AfterConnect 回調中啟動 uv_read_start 並設置狀態。
uv_close(AfterClientClose),回調中 delete clientdatauv_close(AfterClose),析構函數釋放緩衝區uv_mutex_destroy 在 close() 中調用作者提到:「客戶端並發 20 多路超過 uv_write 會 assert 出錯,未找到原因;萬級併發未測試。」
write_req_ 和 write_mutex,並發調用 send() 會阻塞或衝突writebuffer_ 為成員變量,併發 send 會覆蓋數據uv_write_t 未完成前不可重複提交send 內部分配獨立 uv_write_t + 緩衝區(或使用寫隊列)write_req/writebuffer,設計較合理GitHub: https://github.com/wqvbjhc/libuv_tcp
這是一個工程化程度較高的 libuv TCP 封裝,展示了異步網絡編程的核心模式:事件循環、回調驅動、資源生命週期管理、線程安全。適合作為高性能網絡服務的基礎框架,解決 Client 併發寫問題後可支撐更大規模併發。