MST

星途 面试题库

面试题:C语言TCP服务器的性能优化与安全加固

在高并发场景下,使用C语言搭建的Linux TCP服务器可能面临性能瓶颈和安全风险。请从网络配置、内存管理、代码优化等方面阐述如何对服务器进行性能优化;同时,说明可能存在的安全漏洞如缓冲区溢出等,并阐述相应的防范措施以及如何在代码层面实现这些措施。
21.4万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

性能优化

  1. 网络配置
    • 调整内核参数
      • 通过修改/etc/sysctl.conf文件,增大net.ipv4.tcp_max_syn_backlog,增加TCP半连接队列长度,应对高并发的连接请求。例如,设置为net.ipv4.tcp_max_syn_backlog = 10240。修改后执行sudo sysctl -p使配置生效。
      • 增大net.core.somaxconn,它决定了socket监听队列的最大长度。可以设置为net.core.somaxconn = 4096
    • 使用零拷贝技术
      • 在Linux下,可以利用sendfile函数实现零拷贝。例如:
#include <sys/socket.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    int filefd = open("example.txt", O_RDONLY);
    struct sockaddr_in addr;
    // 初始化addr...
    bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
    listen(sockfd, 5);
    int clientfd = accept(sockfd, NULL, NULL);
    off_t offset = 0;
    off_t len = lseek(filefd, 0, SEEK_END);
    lseek(filefd, 0, SEEK_SET);
    sendfile(clientfd, filefd, &offset, len);
    close(sockfd);
    close(filefd);
    close(clientfd);
    return 0;
}
  1. 内存管理
    • 使用内存池
      • 预先分配一块较大的内存空间作为内存池。例如:
#include <stdio.h>
#include <stdlib.h>

#define MEM_POOL_SIZE 1024 * 1024
#define BLOCK_SIZE 128

typedef struct Block {
    struct Block *next;
} Block;

typedef struct MemoryPool {
    Block *freeList;
} MemoryPool;

MemoryPool *createMemoryPool() {
    MemoryPool *pool = (MemoryPool *)malloc(sizeof(MemoryPool));
    pool->freeList = (Block *)malloc(MEM_POOL_SIZE);
    Block *current = pool->freeList;
    for (int i = 0; i < (MEM_POOL_SIZE / BLOCK_SIZE - 1); i++) {
        current->next = (Block *)((char *)current + BLOCK_SIZE);
        current = current->next;
    }
    current->next = NULL;
    return pool;
}

void *allocateFromPool(MemoryPool *pool) {
    if (pool->freeList == NULL) {
        return NULL;
    }
    Block *block = pool->freeList;
    pool->freeList = block->next;
    return block;
}

void freeToPool(MemoryPool *pool, void *block) {
    ((Block *)block)->next = pool->freeList;
    pool->freeList = (Block *)block;
}
- **减少内存碎片**:
  - 采用内存对齐的方式分配内存,例如使用`posix_memalign`函数。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main() {
    void *ptr;
    int ret = posix_memalign(&ptr, 16, 1024);
    if (ret != 0) {
        perror("posix_memalign");
        return 1;
    }
    free(ptr);
    return 0;
}
  1. 代码优化
    • 采用多线程或多进程模型
      • 多线程:使用pthread库,例如:
#include <pthread.h>
#include <stdio.h>

void *threadFunction(void *arg) {
    printf("Thread is running\n");
    return NULL;
}

int main() {
    pthread_t thread;
    int ret = pthread_create(&thread, NULL, threadFunction, NULL);
    if (ret != 0) {
        perror("pthread_create");
        return 1;
    }
    pthread_join(thread, NULL);
    return 0;
}
  - **多进程**:使用`fork`函数,例如:
#include <stdio.h>
#include <unistd.h>

int main() {
    pid_t pid = fork();
    if (pid < 0) {
        perror("fork");
        return 1;
    } else if (pid == 0) {
        printf("Child process\n");
    } else {
        printf("Parent process\n");
        wait(NULL);
    }
    return 0;
}
- **优化算法和数据结构**:
  - 例如,使用哈希表来快速查找连接信息,代替线性查找。

安全漏洞及防范措施

  1. 缓冲区溢出
    • 防范措施
      • 边界检查:在使用数组等缓冲区时,确保访问不越界。例如:
#include <stdio.h>
#include <string.h>

#define BUFFER_SIZE 100

void safeCopy(char *dest, const char *src) {
    if (strlen(src) < BUFFER_SIZE) {
        strcpy(dest, src);
    } else {
        strncpy(dest, src, BUFFER_SIZE - 1);
        dest[BUFFER_SIZE - 1] = '\0';
    }
}
  - **使用安全函数**:例如使用`snprintf`代替`sprintf`,`strncpy`代替`strcpy`等。
#include <stdio.h>

int main() {
    char buffer[100];
    int ret = snprintf(buffer, sizeof(buffer), "This is a test string");
    return 0;
}
  1. 整数溢出
    • 防范措施
      • 检查运算结果:在进行可能导致溢出的运算前,先检查结果是否会溢出。例如,在进行乘法运算前:
#include <stdio.h>
#include <limits.h>

int safeMultiply(int a, int b) {
    if (a != 0 && b > INT_MAX / a) {
        // 处理溢出情况,例如返回错误码
        return -1;
    }
    return a * b;
}
  1. SQL注入(若涉及数据库操作)
    • 防范措施
      • 使用参数化查询:如果使用SQLite,例如:
#include <sqlite3.h>
#include <stdio.h>

int main() {
    sqlite3 *db;
    sqlite3_stmt *stmt;
    const char *sql = "SELECT * FROM users WHERE username =? AND password =?";
    const char *data = "Callback function data";
    int rc = sqlite3_open("test.db", &db);
    if (rc) {
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        return rc;
    }
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "Failed to prepare statement: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return rc;
    }
    sqlite3_bind_text(stmt, 1, "user", -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 2, "pass", -1, SQLITE_STATIC);
    while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
        printf("Result: %s\n", sqlite3_column_text(stmt, 0));
    }
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return 0;
}