多线程-阻塞IO模型

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <errno.h>

#define MAX_SIZE 2048
#define SERVER_PORT 8000

// 工作线程函数:处理单个客户端的阻塞 I/O
void* handle_client(void* arg) {
    int client_fd = (long)arg;
    pthread_detach(pthread_self()); // 自动回收线程资源

    long thread_id = (long)pthread_self();
    printf("Thread %ld: Started, handling client socket %d\n", thread_id, client_fd);

    char buffer[MAX_SIZE];
    ssize_t recv_len;

    // 阻塞循环读取
    while ((recv_len = recv(client_fd, buffer, MAX_SIZE - 1, 0)) > 0) {
        buffer[recv_len] = '\0';
        printf("Thread %ld: Received %zd bytes from %d: %s", 
               thread_id, recv_len, client_fd, buffer);

        // 回显给客户端
        ssize_t sent = send(client_fd, buffer, recv_len, 0);
        if (sent < 0) {
            perror("send failed");
            break;
        }
        printf("Thread %ld: Sent %zd bytes back to client %d\n", 
               thread_id, sent, client_fd);
    }

    // recv 返回 0:客户端正常关闭连接
    if (recv_len == 0) {
        printf("Thread %ld: Client %d disconnected gracefully.\n", thread_id, client_fd);
    } 
    // recv 返回 -1:错误
    else {
        if (errno == ECONNRESET) {
            printf("Thread %ld: Client %d forced close (RST).\n", thread_id, client_fd);
        } else {
            perror("recv error");
        }
    }

    // 关闭客户端 socket
    close(client_fd);
    printf("Thread %ld: Closed socket %d and exiting.\n", thread_id, client_fd);

    return NULL;
}

int main() {
    int server_fd;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_len = sizeof(client_addr);

    // 创建 socket
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    // 设置端口复用,避免 "Address already in use"
    int opt = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    // 绑定地址
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(SERVER_PORT);

    if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind failed");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    // 监听
    if (listen(server_fd, 10) < 0) {
        perror("listen failed");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    printf("TCP Server started on port %d\n", SERVER_PORT);
    printf("Waiting for incoming connections...\n");

    // 主循环:accept 客户端并创建线程
    while (1) {
        int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
        if (client_fd < 0) {
            perror("accept failed");
            continue; // 继续监听
        }

        // 获取客户端 IP
        char client_ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);
        int client_port = ntohs(client_addr.sin_port);

        printf("Accepted connection from %s:%d (socket %d)\n", 
               client_ip, client_port, client_fd);

        // 创建线程处理该客户端
        pthread_t thread_id;
        if (pthread_create(&thread_id, NULL, handle_client, (void*)(long)client_fd) != 0) {
            perror("pthread_create failed");
            printf("Failed to create thread for client %d, closing connection.\n", client_fd);
            close(client_fd);
        }
        // 注意:线程已 detach,无需 join
    }

    // 正常不会执行到这里
    close(server_fd);
    return 0;
}
posted @ 2018-11-18 21:09  osbreak  阅读(175)  评论(0)    收藏  举报