int uv_tcp_connect(uv_connect_t* req,
uv_tcp_t* handle,
const struct sockaddr* addr,
uv_connect_cb cb)
当建立连接后,回调函数on_connect
会被调用。回调函数会接收到一个uv_connect_t结构的数据,它的handle
指向通信的socket。这点非常重要:
因为你在进行连接前要先准备好uv_tcp_t的socket和uv_connect_t的connect_req:
uv_tcp_t* socket = (uv_tcp_t*)malloc(sizeof(uv_tcp_t));
uv_tcp_init(loop, socket);
uv_connect_t* connect_req = (uv_connect_t*)malloc(sizeof(uv_connect_t));
什么时候释放这两个资源是个问题, 首先官方文档说了,“当连接建立或发生连接错误时进行回调。”,却没说这个返回值干毛用。
测试发现,无论这次连接成功与否,uv_tcp_connet的返回值都是0,这就比较扯淡了。
所以判断连接是否成功,以及资源释放的逻辑都应放在uv_connect_cb的回调中:
void on_connect(uv_connect_t *req, int status) {
if (status < 0) {
fprintf(stderr, "connect failed error %s\n", uv_err_name(status));
free(req);
return;
}
uv_read_start((uv_stream_t*) req->handle, alloc_buffer, on_read);
free(req);
}
注意,这里只free了req, 原因是:
传到回调函数中的uv_connect_t结构的handle
指向了通信的socket,也及你malloc出来的uv_tcp_t*的socket.
如果你再去uv_close((uv_handle_t*)socket,NULL); 会crash的。
int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb);
void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
buf->base = malloc(suggested_size);
buf->len = suggested_size;
}
这就意味着这块内存需要你自己维护(在不用时正确释放这块内存)。
void on_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) {
if (nread < 0) {
if (nread != UV_EOF)
fprintf(stderr, "Read error %s\n", uv_err_name(nread));
uv_close((uv_handle_t*) client, NULL);
free(buf->base);
free(client);
return;
}
char *data = (char*) malloc(sizeof(char) * (nread+1));
data[nread] = '\0';
strncpy(data, buf->base, nread);
fprintf(stderr, "%s", data);
free(data);
free(buf->base);
}
无论这次读取是否发生错误(根据nread判断),都要及时释放申请的buf,为毛发生错误时要释放client值得一思。
完整代码(引自官方示例代码):
#include
#include
#include
#include
uv_loop_t *loop;
void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
buf->base = malloc(suggested_size);
buf->len = suggested_size;
}
void on_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) {
if (nread < 0) {
if (nread != UV_EOF)
fprintf(stderr, "Read error %s\n", uv_err_name(nread));
uv_close((uv_handle_t*) client, NULL);
free(buf->base);
free(client);
return;
}
char *data = (char*) malloc(sizeof(char) * (nread+1));
data[nread] = '\0';
strncpy(data, buf->base, nread);
fprintf(stderr, "%s", data);
free(data);
free(buf->base);
}
void on_connect(uv_connect_t *req, int status) {
if (status < 0) {
fprintf(stderr, "connect failed error %s\n", uv_err_name(status));
free(req);
return;
}
uv_read_start((uv_stream_t*) req->handle, alloc_buffer, on_read);
free(req);
}
void on_resolved(uv_getaddrinfo_t *resolver, int status, struct addrinfo *res) {
if (status < 0) {
fprintf(stderr, "getaddrinfo callback error %s\n", uv_err_name(status));
return;
}
char addr[17] = {'\0'};
uv_ip4_name((struct sockaddr_in*) res->ai_addr, addr, 16);
fprintf(stderr, "%s\n", addr);
uv_connect_t *connect_req = (uv_connect_t*) malloc(sizeof(uv_connect_t));
uv_tcp_t *socket = (uv_tcp_t*) malloc(sizeof(uv_tcp_t));
uv_tcp_init(loop, socket);
uv_tcp_connect(connect_req, socket, (const struct sockaddr*) res->ai_addr, on_connect);
uv_freeaddrinfo(res);
}
int main() {
loop = uv_default_loop();
struct addrinfo hints;
hints.ai_family = PF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = 0;
uv_getaddrinfo_t resolver;
fprintf(stderr, "irc.freenode.net is... ");
int r = uv_getaddrinfo(loop, &resolver, on_resolved, "irc.freenode.net", "6667", &hints);
if (r) {
fprintf(stderr, "getaddrinfo call error %s\n", uv_err_name(r));
return 1;
}
return uv_run(loop, UV_RUN_DEFAULT);
}