Skip to content

Instantly share code, notes, and snippets.

@teraPacket
Created August 16, 2017 03:43
Show Gist options
  • Save teraPacket/16006eb91ab3f8d3b3d5de33190acc7c to your computer and use it in GitHub Desktop.
Save teraPacket/16006eb91ab3f8d3b3d5de33190acc7c to your computer and use it in GitHub Desktop.
example TCP client using libuv (version 1.0)
#include <stdio.h>
#include <stdlib.h>
#include <uv.h>
//based on https://gist.githubusercontent.com/snatchev/5255976/
//raw/8392c42d719bb775053036e32b21affdf932c1b7/libuv-tcp-client.c
//which was based on libuv 0.1, there is considerable difference there.
static void on_close(uv_handle_t* handle);
static void on_connect(uv_connect_t* req, int status);
static void on_write(uv_write_t* req, int status);
static uv_loop_t *loop;
static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
*buf = uv_buf_init(malloc(size), size);
}
void on_close(uv_handle_t* handle)
{
printf("closed.");
}
void on_write(uv_write_t* req, int status)
{
if (status) {
perror( "uv_write error ");
return;
}
printf("wrote.\n");
free(req);
//uv_close((uv_handle_t*)req->handle, on_close);
}
void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf)
{
printf("on_read. %p\n",tcp);
if(nread >= 0) {
//printf("read: %s\n", tcp->data);
printf("read: %s\n", buf->base);
}
else {
//we got an EOF
uv_close((uv_handle_t*)tcp, on_close);
}
//cargo-culted
free(buf->base);
}
void write2(uv_stream_t* stream, char *data, int len2) {
uv_buf_t buffer[] = {
{.base = data, .len = len2}
};
uv_write_t *req = malloc(sizeof(uv_write_t));
uv_write(req, stream, buffer, 1, on_write);
}
void on_connect(uv_connect_t* connection, int status)
{
if (status < 0) {
printf("failed to connect\n"); return;
}
printf("connected. %p %d\n",connection, status);
uv_stream_t* stream = connection->handle;
free(connection);
write2(stream, "echo world!", 12);
uv_read_start(stream, alloc_cb, on_read);
}
void startConn(char *host, int port) {
uv_tcp_t *pSock = malloc(sizeof(uv_tcp_t));
uv_tcp_init(loop, pSock);
uv_tcp_keepalive(pSock, 1, 60);
struct sockaddr_in dest;
uv_ip4_addr(host, port, &dest);
uv_connect_t *pConn = malloc(sizeof(uv_connect_t));
printf("allocated %p\n", pConn);
uv_tcp_connect(pConn, pSock, (const struct sockaddr*)&dest, on_connect);
}
int main(int argc, char **argv) {
loop = uv_default_loop();
int i;
for (i=0; i<10; i++)
startConn("127.0.0.1", 80);
uv_run(loop, UV_RUN_DEFAULT);
}
@teraPacket
Copy link
Author

compile it as

gcc -o tcp_client tcp_client.c -luv

@kYroL01
Copy link

kYroL01 commented Feb 1, 2023

Hi @teraPacket and thanks for this example.
I did some additional test using valgrind and I think in function on_close you need to add

free(handle);

Check the output of valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all tcp_client

  1. Without free(handle)
==3228== HEAP SUMMARY:
==3228==     in use at exit: 2,736 bytes in 11 blocks
==3228==   total heap usage: 43 allocs, 32 frees, 662,128 bytes allocated
==3228== 
==3228== 256 bytes in 1 blocks are still reachable in loss record 1 of 3
==3228==    at 0x4837D7B: realloc (vg_replace_malloc.c:826)
==3228==    by 0x486DAE0: uv__io_start (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
==3228==    by 0x4877E18: uv__tcp_connect (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
==3228==    by 0x1094A3: startConn (libuv_tcp_client.c:79)
==3228==    by 0x1094DB: main (libuv_tcp_client.c:86)
==3228== 
==3228== 1,984 bytes in 8 blocks are indirectly lost in loss record 2 of 3
==3228==    at 0x483577F: malloc (vg_replace_malloc.c:299)
==3228==    by 0x10941D: startConn (libuv_tcp_client.c:70)
==3228==    by 0x1094DB: main (libuv_tcp_client.c:86)
==3228== 
==3228== 2,480 (496 direct, 1,984 indirect) bytes in 2 blocks are definitely lost in loss record 3 of 3
==3228==    at 0x483577F: malloc (vg_replace_malloc.c:299)
==3228==    by 0x10941D: startConn (libuv_tcp_client.c:70)
==3228==    by 0x1094DB: main (libuv_tcp_client.c:86)
==3228== 
==3228== LEAK SUMMARY:
==3228==    definitely lost: 496 bytes in 2 blocks
==3228==    indirectly lost: 1,984 bytes in 8 blocks
==3228==      possibly lost: 0 bytes in 0 blocks
==3228==    still reachable: 256 bytes in 1 blocks
==3228==         suppressed: 0 bytes in 0 blocks
==3228== 
==3228== For counts of detected and suppressed errors, rerun with: -v
==3228== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0
  1. With free(handle)
==3236== HEAP SUMMARY:
==3236==     in use at exit: 256 bytes in 1 blocks
==3236==   total heap usage: 43 allocs, 42 frees, 662,128 bytes allocated
==3236== 
==3236== 256 bytes in 1 blocks are still reachable in loss record 1 of 1
==3236==    at 0x4837D7B: realloc (vg_replace_malloc.c:826)
==3236==    by 0x486DAE0: uv__io_start (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
==3236==    by 0x4877E18: uv__tcp_connect (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
==3236==    by 0x1094AF: startConn (libuv_tcp_client.c:79)
==3236==    by 0x1094E7: main (libuv_tcp_client.c:86)
==3236== 
==3236== LEAK SUMMARY:
==3236==    definitely lost: 0 bytes in 0 blocks
==3236==    indirectly lost: 0 bytes in 0 blocks
==3236==      possibly lost: 0 bytes in 0 blocks
==3236==    still reachable: 256 bytes in 1 blocks
==3236==         suppressed: 0 bytes in 0 blocks
==3236== 
==3236== For counts of detected and suppressed errors, rerun with: -v
==3236== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

I hope it could be useful for anyone checking a good libuv 1.0 example

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment