concurrent server using LibUV

26 views
Skip to first unread message

nilsocket

unread,
Feb 12, 2020, 8:00:47 AM2/12/20
to libuv
#include <stdlib.h>
#include <uv.h>

uv_loop_t* loop;
uv_tcp_t server;
struct sockaddr_in addr;

void on_new_connection(uv_stream_t* server, int status);
void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
void serve_client(uv_work_t* req);
void on_write(uv_write_t* req, int status);

int main() {
int r;

loop = uv_default_loop();

uv_tcp_init(loop, &server);

uv_ip4_addr("0.0.0.0", 8080, &addr);
uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);

if ((r = uv_listen((uv_stream_t*)&server, 100, on_new_connection))) {
fprintf(stderr, "Listen error %s\n", uv_strerror(r));
return 1;
}

return uv_run(loop, UV_RUN_DEFAULT);
}

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_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_work_t* work_req = malloc(sizeof(uv_work_t));
work_req->data = client;
uv_queue_work(client->loop, work_req, serve_client, NULL);
}
}

void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
*buf = uv_buf_init((char*)malloc(suggested_size), suggested_size);
}

void serve_client(uv_work_t* req) {
uv_read_start((uv_stream_t*)req->data, alloc_buffer, read_cb);
}

void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
if (nread < 0) {
if (nread == UV_EOF) {
uv_close((uv_handle_t*)stream, NULL);
}
} else if (nread > 0) {
uv_write_t req;

uv_buf_t* tempBuf = malloc(sizeof(uv_buf_t));
*tempBuf = *buf;

req.data = tempBuf;
tempBuf->len = nread;

uv_write(&req, stream, tempBuf, 1, on_write);
} else {
uv_close((uv_handle_t*)stream, NULL);
}
}

void on_write(uv_write_t* req, int status) {
uv_buf_t* buf = (uv_buf_t*)req->data;
free(buf->base);
free(buf);
}

This is a simple program, which echoes data back to client.

But when I try to connect multiple connections at a time, it crashes, can somebody tell me why it's crashing?

I'm attaching a client program, which connects to server, to write and read data(`hello`).
To run  it:
go run main.go x
Where `x`, represents no.of concurrent connections.

Thank you.

Santiago Gimeno

unread,
Feb 12, 2020, 8:46:56 AM2/12/20
to li...@googlegroups.com
Hi,

It seems the problem is that you're allocating the `uv_write_t req` in the stack.

br

--
You received this message because you are subscribed to the Google Groups "libuv" group.
To unsubscribe from this group and stop receiving emails from it, send an email to libuv+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/libuv/5a8a3da4-dc9d-4e92-81c8-5194a25402bc%40googlegroups.com.

nilsocket

unread,
Feb 12, 2020, 11:19:17 AM2/12/20
to libuv
Forgot to attach attachment.
main.go

nilsocket

unread,
Feb 12, 2020, 11:19:17 AM2/12/20
to li...@googlegroups.com
Thanks a lot for responding, I have moved `uv_write_req` to heap, but still it is crashing most of the time. when concurrent no.of connections is 100.

Sometimes, it is working, but it is not working most of the time.

On Wed, Feb 12, 2020 at 7:16 PM Santiago Gimeno <santiag...@gmail.com> wrote:

Thank you

Santiago Gimeno

unread,
Feb 12, 2020, 12:35:39 PM2/12/20
to li...@googlegroups.com
Hi again,

I see you're handling reads in a different thread. Afaik, that's not supported. From the documentation here: http://docs.libuv.org/en/v1.x/design.html#the-i-o-loop

"The I/O (or event) loop is the central part of libuv. It establishes the content for all I/O operations, and it’s meant to be tied to a single thread. One can run multiple event loops as long as each runs in a different thread. The libuv event loop (or any other API involving the loop or handles, for that matter) is not thread-safe except where stated otherwise."

br

--
You received this message because you are subscribed to the Google Groups "libuv" group.
To unsubscribe from this group and stop receiving emails from it, send an email to libuv+un...@googlegroups.com.

nilsocket

unread,
Feb 13, 2020, 2:58:51 AM2/13/20
to libuv

I was trying to handle reads in different thread, because I don't want to make main loop heavy(time-consuming, because of my work).

I want to off-load serving requests to threads in thread pool, how can I achieve this?

Or is it that, I can't off-load serving requests, if it contains any libuv functions inside it, like reading data from socket,...?
If that is the case, then isn't it going to increase load on single thread (main-loop thread), all libuv read calls are going to happen from here?

Is there any possibility, to off-load serving a request to one of the thread in thread-pool?

Thank you.

Santiago Gimeno

unread,
Feb 13, 2020, 3:47:55 AM2/13/20
to li...@googlegroups.com
Hello,

You can do it by creating your own threads with their own uv_loop_t and passing them the handles. You can find a similar scenario in https://github.com/libuv/libuv/blob/v1.x/test/benchmark-multi-accept.c

br

--
You received this message because you are subscribed to the Google Groups "libuv" group.
To unsubscribe from this group and stop receiving emails from it, send an email to libuv+un...@googlegroups.com.

nilsocket

unread,
Feb 13, 2020, 5:27:40 AM2/13/20
to li...@googlegroups.com
Thanks a lot, I will look into it.



--
Thank you
Reply all
Reply to author
Forward
0 new messages