preveen-stack / test

0 stars 0 forks source link

libuv #23

Open preveen-stack opened 1 year ago

preveen-stack commented 1 year ago

Libuv is a multi-platform library written in C that provides asynchronous event-driven I/O, timers, and other functionality to enable high-performance network and file system operations. It was originally developed as part of the Node.js project to provide an abstraction layer between the underlying operating system and Node's event loop.

Libuv provides a consistent API for asynchronous I/O operations on various platforms, including Linux, macOS, Windows, and Unix-like systems. It provides an event loop that can handle I/O events, timers, and signals, and also supports features such as TCP and UDP socket handling, file system operations, child process management, and thread pools.

One of the main benefits of using libuv is that it allows developers to write code that is both efficient and portable across different operating systems. It provides a consistent interface to I/O operations, regardless of the underlying platform, and handles many of the platform-specific details automatically.

In addition to being used by Node.js, libuv is also used by other software projects that require high-performance network and file system operations, such as the Julia programming language and the Apache CouchDB database.

preveen-stack commented 1 year ago

Here's an example of how to use libuv in C to create a simple TCP server that listens on a specified port and sends back a "Hello, world!" message to any client that connects to it:

#include <stdio.h>
#include <stdlib.h>
#include <uv.h>

#define DEFAULT_PORT 8000

void on_new_connection(uv_stream_t *server, int status) {
  if (status < 0) {
    fprintf(stderr, "Error on_new_connection: %s\n", uv_strerror(status));
    return;
  }

  uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t));
  uv_tcp_init(uv_default_loop(), client);

  if (uv_accept(server, (uv_stream_t*) client) == 0) {
    uv_buf_t buffer = uv_buf_init("Hello, world!\n", 14);
    uv_write_t *req = (uv_write_t*) malloc(sizeof(uv_write_t));
    uv_write(req, (uv_stream_t*) client, &buffer, 1, NULL);
  }
  else {
    uv_close((uv_handle_t*) client, NULL);
  }
}

int main(int argc, char **argv) {
  uv_loop_t *loop = uv_default_loop();

  uv_tcp_t server;
  uv_tcp_init(loop, &server);

  struct sockaddr_in bind_addr;
  uv_ip4_addr("0.0.0.0", DEFAULT_PORT, &bind_addr);

  uv_tcp_bind(&server, (const struct sockaddr*)&bind_addr, 0);

  int status = uv_listen((uv_stream_t*) &server, 128, on_new_connection);
  if (status != 0) {
    fprintf(stderr, "Error uv_listen: %s\n", uv_strerror(status));
    return 1;
  }

  return uv_run(loop, UV_RUN_DEFAULT);
}

In this example, we first initialize a libuv event loop using uv_default_loop(). Then, we create a TCP server using uv_tcp_init() and bind it to a specified port using uv_tcp_bind(). We use uv_listen() to listen for incoming connections and pass a callback function (on_new_connection) that will be called when a new connection is established.

The on_new_connection function is responsible for handling new connections. It first checks if there was an error on the connection, and if not, it accepts the new client connection using uv_accept(). If the connection is successful, it sends a "Hello, world!" message back to the client using uv_write(). Finally, it closes the client connection using uv_close().

In the main() function, we run the event loop using uv_run() and pass UV_RUN_DEFAULT as the mode. This will cause the event loop to block until there are no more events to handle.

preveen-stack commented 1 year ago

To compile and run the code on macOS, follow these steps:

  1. Make sure you have the latest version of Xcode installed, which includes the Clang C compiler.

  2. Open a terminal and navigate to the directory containing the source code file.

  3. Compile the source code using the following command:

    clang -Wall -g -o server server.c -luv

    This will compile the code and link it with the libuv library.

  4. Run the server using the following command:

    ./server

    This will start the server and it will listen for incoming connections on port 8000.

  5. To test the server, open a new terminal window and use the following command to connect to the server:

    telnet localhost 8000

    You should see the "Hello, world!" message printed in the terminal window where the server is running.

Note: If you encounter any errors during compilation or execution, make sure that you have installed libuv on your system and that the library is in the search path. You can install libuv using a package manager like Homebrew or MacPorts, or you can download the source code from the libuv GitHub repository and build it yourself.

preveen-stack commented 1 year ago
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uv.h>

#define DEFAULT_PORT 8000

typedef struct {
  uv_tcp_t handle;
  uv_write_t write_req;
  uv_buf_t write_buf;
} client_t;

void on_client_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
  if (nread > 0) {
    client_t *client = (client_t*) stream->data;
    uv_write(&client->write_req, stream, buf, 1, NULL);
  }
  else if (nread < 0) {
    if (nread != UV_EOF) {
      fprintf(stderr, "Error on_client_read: %s\n", uv_strerror(nread));
    }
    uv_close((uv_handle_t*) stream, NULL);
    free(buf->base);
    free(client);
  }
}

void on_new_connection(uv_stream_t *server, int status) {
  if (status < 0) {
    fprintf(stderr, "Error on_new_connection: %s\n", uv_strerror(status));
    return;
  }

  client_t *client = (client_t*) malloc(sizeof(client_t));
  uv_tcp_init(uv_default_loop(), &client->handle);

  if (uv_accept(server, (uv_stream_t*) &client->handle) == 0) {
    client->handle.data = client;
    uv_read_start((uv_stream_t*) &client->handle, (uv_alloc_cb) uv_buf_init, on_client_read);
  }
  else {
    uv_close((uv_handle_t*) &client->handle, NULL);
    free(client);
  }
}

int main(int argc, char **argv) {
  uv_loop_t *loop = uv_default_loop();

  uv_tcp_t server;
  uv_tcp_init(loop, &server);

  struct sockaddr_in bind_addr;
  uv_ip4_addr("0.0.0.0", DEFAULT_PORT, &bind_addr);

  uv_tcp_bind(&server, (const struct sockaddr*)&bind_addr, 0);

  int status = uv_listen((uv_stream_t*) &server, 128, on_new_connection);
  if (status != 0) {
    fprintf(stderr, "Error uv_listen: %s\n", uv_strerror(status));
    return 1;
  }

  return uv_run(loop, UV_RUN_DEFAULT);
}