Libuv TCP服务器

libuv TCP 服务器端的建立流程如下:

1.uv_tcp_init建立tcp句柄。
2.uv_tcp_bind绑定。
3.uv_listen建立监听,当有新的连接到来时,激活调用回调函数。
4.uv_accept接收链接。
5.使用stream操作来和客户端通信。

TCP服务器的listen

例如我们要监听本地服务器的3456端口

#define DEFAULT_PORT 3456
int main() 
{
    uv_loop_t* loop = uv_default_loop();

    uv_tcp_t server;
    uv_tcp_init(loop, &server);

    uv_ip4_addr("0.0.0.0", DEFAULT_PORT, &addr);

    uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);
    int r = uv_listen((uv_stream_t*) &server, DEFAULT_BACKLOG, on_new_connection);
    if (r) 
    {
        fprintf(stderr, "Listen error %sn", uv_strerror(r));
        return 1;
    }
    return uv_run(loop, UV_RUN_DEFAULT);
}

当uv_listen执行成功后。服务进入默认的循环中。

TCP服务器完整示例

假如服务器被被客户端连上后,接收从客户端的字符串并打印出来,然后再给客户端发送一个字符串以示回应。
完整的代码如下:

// libuv-server.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include"uv.h"

#pragma comment(lib,"libuv.lib")
#pragma comment(lib,"Ws2_32.lib")
#pragma comment(lib,"iphlpapi.lib")
#pragma comment(lib,"Userenv.lib")
#pragma comment(lib,"Psapi.lib")


void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
{
    buf->base = (char*)malloc(suggested_size);
    buf->len = suggested_size;
}


typedef struct
{
    uv_write_t req;
    uv_buf_t buf;
}write_req_t;


void echo_write(uv_write_t* req, int status)
{
    if (status)
    {
        fprintf(stderr, "Write error %s\n", uv_strerror(status));
        return;
    }

    write_req_t *wr = (write_req_t*)req;
    free(wr->buf.base);
    free(wr);
}
void read_cb(uv_stream_t* stream,ssize_t nread,const uv_buf_t* buf)
{
    if (nread > 0)
    {
        buf->base[nread] = '\0';
        printf("%s\n", buf->base);

        write_req_t *req = (write_req_t *)malloc(sizeof(write_req_t));
        req->buf.base = (char*)malloc(4);
        req->buf.len = 4;
        memcpy(req->buf.base, "456", 4);
        uv_write((uv_write_t *)req, stream, &req->buf, 1, echo_write);
    }

    if (buf->base != NULL)
    {
        free(buf->base);
    }

}


void on_new_connection(uv_stream_t *server, int status)
{
    if (status < 0) 
    {
        fprintf(stderr, "New connection error %s\n", uv_strerror(status));
        return;
    }
    uv_loop_t* loop = uv_default_loop();


    uv_tcp_t *client = (uv_tcp_t*)malloc(sizeof(uv_tcp_t));
    uv_tcp_init(loop, client);
    if (uv_accept(server, (uv_stream_t*)client) == 0)
    {
        uv_read_start((uv_stream_t*)client, alloc_buffer, read_cb);
    }
    else 
    {
        uv_close((uv_handle_t*)client, NULL);
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    uv_loop_t* loop = uv_default_loop();

    uv_tcp_t server;
    uv_tcp_init(loop, &server);

    sockaddr_in addr;
    uv_ip4_addr("0.0.0.0", 3333, &addr);

    uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);
    int DEFAULT_PORT = 0;
    int r = uv_listen((uv_stream_t*)&server, 1, on_new_connection);
    if (r) 
    {
        fprintf(stderr, "Listen error %s\n", uv_strerror(r));
        return 1;
    }
    return uv_run(loop, UV_RUN_DEFAULT);
}