Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need more examples: C Server #62

Open
kassane opened this issue Aug 22, 2023 · 1 comment
Open

Need more examples: C Server #62

kassane opened this issue Aug 22, 2023 · 1 comment
Labels
bug Something isn't working

Comments

@kassane
Copy link

kassane commented Aug 22, 2023

Hi @mitchellh,

Nice hard work (for you and all your collaborators) to make this library.

I have been playing with the xev api for C code on linux today.
However, some trouble was encountered when running the same code with or without xev.

Client: curl 127.0.0.1:8000.

Without xev

C code - server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 8000 // The port number for the server to listen on

int main() {
    int server_socket, client_socket;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
    
    // Create a socket
    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket == -1) {
        perror("Socket creation failed");
        exit(1);
    }
    
    // Bind the socket to an IP address and port
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY; // Listen on all available network interfaces
    server_addr.sin_port = htons(PORT);
    
    if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        perror("Socket binding failed");
        close(server_socket);
        exit(1);
    }
    
    // Listen for incoming connections
    if (listen(server_socket, 10) == -1) {
        perror("Listen failed");
        close(server_socket);
        exit(1);
    }
    
    printf("Server listening on port %d...\n", PORT);
    
    while (1) {
        // Accept a client connection
        client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_addr_len);
        if (client_socket == -1) {
            perror("Accept failed");
            continue; // Continue listening for other connections
        }
        
        printf("Connection accepted from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
        
        // Handle the client connection (in this example, we simply echo back received data)
        char buffer[1024];
        ssize_t bytes_received;
        
        while ((bytes_received = recv(client_socket, buffer, sizeof(buffer), 0)) > 0) {
            buffer[bytes_received] = '\0'; // Null-terminate the received data
            printf("Received: %s", buffer);
            
            // Echo back to the client
            send(client_socket, buffer, bytes_received, 0);
        }
        
        // Close the client socket
        close(client_socket);
        printf("Connection closed by %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
    }
    
    // Close the server socket (this part will not be reached in this example)
    close(server_socket);
    
    return 0;
}

Output

$> ./server_example 
Server listening on port 8000...
Connection accepted from 127.0.0.1:42220
Received: GET / HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: curl/8.2.1
Accept: */*

Connection closed by 127.0.0.1:42220

With xev

C code - server
#include "xev.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 8000 // The port number for the server to listen on

void on_connection(xev_loop* loop, xev_completion* c, int result, void* userdata) {
    int server_socket = *(int*)userdata;

    int client_socket = accept(server_socket, NULL, NULL);
    if (client_socket == -1) {
        perror("Accept failed");
        return;
    }

    char buffer[1024];
    ssize_t bytes_received;

    while ((bytes_received = recv(client_socket, buffer, sizeof(buffer), 0)) > 0) {
        buffer[bytes_received] = '\0'; // Null-terminate the received data
        printf("Received: %s", buffer);

        // Echo back to the client
        send(client_socket, buffer, bytes_received, 0);
    }

    close(client_socket);
}

int main() {
    xev_loop loop;
    if (xev_loop_init(&loop) != 0) {
        fprintf(stderr, "Failed to initialize event loop\n");
        return 1;
    }

    int server_socket, client_socket;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_addr_len = sizeof(client_addr);

    // Create a socket
    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket == -1) {
        perror("Socket creation failed");
        exit(1);
    }

    // Bind the socket to an IP address and port
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY; // Listen on all available network interfaces
    server_addr.sin_port = htons(PORT);

    if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        perror("Socket binding failed");
        close(server_socket);
        exit(1);
    }

    // Listen for incoming connections
    if (listen(server_socket, 10) == -1) {
        perror("Listen failed");
        close(server_socket);
        exit(1);
    }

    printf("Server listening on port %d...\n", PORT);

    // Pass the server_socket as user data to the connection handler
    int user_data = server_socket;
    xev_completion completion;
    xev_completion_zero(&completion);
    xev_threadpool_task task;
    xev_threadpool_task_init(&task, (xev_task_cb)on_connection);

    xev_threadpool_batch batch;
    xev_threadpool_batch_init(&batch);
    xev_threadpool_batch_push_task(&batch, &task);

    xev_threadpool threadpool;
    xev_threadpool_init(&threadpool, NULL);
    xev_threadpool_schedule(&threadpool, &batch);

    xev_threadpool_deinit(&threadpool);

    xev_loop_run(&loop, XEV_RUN_UNTIL_DONE);

    xev_loop_deinit(&loop);
    close(server_socket);

    return 0;
}

Output

$> ./server_example 
Server listening on port 8000...
Accept failed: Bad file descriptor

hold client, needed Ctrl+C to stopping.


Note: gcc get errors on data array on header.

include/xev.h:36:44: error: variably modified ‘data’ at file scope
   36 | typedef struct { XEV_ALIGN_T _pad; uint8_t data[XEV_SIZEOF_LOOP - sizeof(XEV_ALIGN_T)]; } xev_loop;
      |                                            ^~~~
include/xev.h:37:44: error: variably modified ‘data’ at file scope
   37 | typedef struct { XEV_ALIGN_T _pad; uint8_t data[XEV_SIZEOF_COMPLETION - sizeof(XEV_ALIGN_T)]; } xev_completion;
      |                                            ^~~~
include/xev.h:38:44: error: variably modified ‘data’ at file scope
   38 | typedef struct { XEV_ALIGN_T _pad; uint8_t data[XEV_SIZEOF_WATCHER - sizeof(XEV_ALIGN_T)]; } xev_watcher;
      |                                            ^~~~
include/xev.h:39:44: error: variably modified ‘data’ at file scope
   39 | typedef struct { XEV_ALIGN_T _pad; uint8_t data[XEV_SIZEOF_THREADPOOL - sizeof(XEV_ALIGN_T)]; } xev_threadpool;
      |                                            ^~~~
include/xev.h:40:44: error: variably modified ‘data’ at file scope
   40 | typedef struct { XEV_ALIGN_T _pad; uint8_t data[XEV_SIZEOF_THREADPOOL_BATCH - sizeof(XEV_ALIGN_T)]; } xev_threadpool_batch;
      |                                            ^~~~
include/xev.h:41:44: error: variably modified ‘data’ at file scope
   41 | typedef struct { XEV_ALIGN_T _pad; uint8_t data[XEV_SIZEOF_THREADPOOL_TASK - sizeof(XEV_ALIGN_T)]; } xev_threadpool_task;
      |                                            ^~~~
include/xev.h:42:44: error: variably modified ‘data’ at file scope
   42 | typedef struct { XEV_ALIGN_T _pad; uint8_t data[XEV_SIZEOF_THREADPOOL_CONFIG - sizeof(XEV_ALIGN_T)]; } xev_threadpool_config;
@mitchellh mitchellh added the bug Something isn't working label Aug 22, 2023
@mitchellh
Copy link
Owner

Thanks, the C API is admittedly anemic right now and not well maintained beyond extremely basic tested usage. I'm sure there are many improvements to be made here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants