You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修改Ncat源码实现新连接对应独立文件输出以替代标准输出

Fix: Ncat - Assign Unique Log Files per Client Connection

Hey there, let's break down why your current code isn't working and how to fix it properly.

The Root Problem

Your f variable is declared inside the read_socket function—that means every time this function gets called (whether it's for a new client connection, or the same client sending more data), f gets reset to 0. On top of that, you're incrementing f every time you read a chunk of data, which would split a single client's data across multiple files instead of keeping it all together. That's exactly the opposite of what you want!

The Solution: Bind a Unique ID to Each Client Connection

We need to assign a persistent, unique ID to each client when they first connect, then use that ID for all data from that connection. Ncat already uses a struct fdinfo to track client socket details, so we can extend that to store our file ID.

Step 1: Extend the fdinfo Structure

First, find where struct fdinfo is defined (usually in ncat.h or a related header) and add a field to store the connection's unique file ID:

struct fdinfo {
    // ... keep all existing fields ...
    int file_id; // New: Stores the unique ID for this client's log file
};

Step 2: Add a Global Counter for Unique IDs

Define a global (or module-level) variable to track the next available file ID. Since Ncat typically uses a single-threaded select loop, we don't need heavy thread safety here—but if you're building a multi-threaded version, add a mutex to protect this counter.

static int next_file_id = 0;
// For multi-threaded builds:
// static pthread_mutex_t file_id_mutex = PTHREAD_MUTEX_INITIALIZER;

Step 3: Assign the ID When a New Client Connects

Find the code that handles new client connections (where accept() is called, often in a function like handle_new_connection). When you create a new fdinfo for the client, assign it the next unique ID:

// When initializing a new fdinfo for a connected client
struct fdinfo *new_fdn = create_fdinfo(new_client_fd);
// Lock if multi-threaded: pthread_mutex_lock(&file_id_mutex);
new_fdn->file_id = next_file_id++;
// Unlock if multi-threaded: pthread_mutex_unlock(&file_id_mutex);

Step 4: Rewrite read_socket to Use the Persistent ID

Now update your read_socket function to use the ID stored in the client's fdinfo instead of the local f variable. We'll also optimize by generating the filename once per connection instead of every data chunk:

int read_socket(int recv_fd) {
    char buf[DEFAULT_TCP_BUF_LEN];
    struct fdinfo *fdn;
    int nbytes, pending;
    char filename[20];

    fdn = get_fdinfo(&client_fdlist, recv_fd);
    ncat_assert(fdn != NULL);
    // Generate filename once for this connection
    snprintf(filename, sizeof(filename), "filename_%i", fdn->file_id);

    nbytes = 0;
    do {
        int n, s;
        n = ncat_recv(fdn, buf, 512, &pending);
        if (n <= 0) {
            // Keep your existing cleanup logic here unchanged
            if (o.debug) logdebug("Closing fd %d.\n", recv_fd);
#ifdef HAVE_OPENSSL
            if (o.ssl && fdn->ssl) {
                if (nbytes == 0) SSL_shutdown(fdn->ssl);
                SSL_free(fdn->ssl);
            }
#endif
            close(recv_fd);
            checked_fd_clr(recv_fd, &master_readfds);
            rm_fd(&client_fdlist, recv_fd);
            checked_fd_clr(recv_fd, &master_broadcastfds);
            rm_fd(&broadcast_fdlist, recv_fd);
            conn_inc--;
            if (get_conn_count() == 0)
                checked_fd_clr(STDIN_FILENO, &master_readfds);
            return n;
        } else {
            FILE *fp = fopen(filename, "a");
            if (fp == NULL) {
                fprintf(stderr, "Failed to open log file: %s\n", filename);
                return 0;
            }
            s = fwrite(buf, 1, n, fp);
            fclose(fp);
            nbytes += n;
        }
    } while (pending);
    return nbytes;
}

Bonus Optimization: Avoid Reopening Files

Opening and closing the file every time you read a chunk is inefficient. Instead, open the file when the client connects and store the file pointer in fdinfo, then close it when the connection ends:

  1. Add a FILE *log_fp field to struct fdinfo
  2. Open the file during connection setup:
    snprintf(filename, sizeof(filename), "filename_%i", new_fdn->file_id);
    new_fdn->log_fp = fopen(filename, "w");
    if (new_fdn->log_fp == NULL) {
        // Handle error (e.g., reject the connection or log to stderr)
    }
    
  3. Use the open file in read_socket:
    s = fwrite(buf, 1, n, fdn->log_fp);
    fflush(fdn->log_fp); // Ensure data writes immediately instead of buffering
    
  4. Close the file in the cleanup section of read_socket:
    if (fdn->log_fp != NULL) {
        fclose(fdn->log_fp);
        fdn->log_fp = NULL;
    }
    

内容的提问来源于stack exchange,提问作者Jason Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 01:52:45