全双工: 通信双方 既可以发送,也可以接收数据

1. 利用多线程 或者 多进程, 实现TCP服务器 和 客户端的全双工通信

思路:

服务器和客户端, 在建立通信以后,可以创建线程,在线程编写另一个功能代码

客户端参考:
pthread_handler()
{
   while(1)
   {
       fgets();
        send();  
   } 
}

main()
{
    socket();
    connect();
    pthread_create();
    
    while(1)
    {
        recv();       
    }
}

服务器参考:
pthread_handler()
{
    while(1)
    { 
       fgets();
       send();      
    } 
}

main()
{
   socket();
   bind();
   listen();
   
   accept();
   pthread_create();
   
      while(1)
      {
         recv();         
      } 
}
 客户端示例代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>

#define BUFFER_SIZE 1024

// 接收线程函数
void *client_recv_thread(void *arg) {
    int sock = *(int *)arg; // 从参数中获取socket描述符
    char buffer[BUFFER_SIZE]; // 用于接收数据的缓冲区
    while (1) {
        memset(buffer, 0, BUFFER_SIZE); // 清空缓冲区
        ssize_t bytes_received = recv(sock, buffer, BUFFER_SIZE - 1, 0); // 接收数据
        if (bytes_received <= 0) {
            perror("接收数据失败");
            break; // 如果接收失败,结束线程
        }
        printf("收到信息: %s", buffer); // 打印接收到的信息
    }
    pthread_exit(NULL); // 结束线程
}

int main() {
    int sock; // 客户端socket描述符
    struct sockaddr_in server; // 服务器地址结构
    char buffer[BUFFER_SIZE]; // 用于发送数据的缓冲区
    sock = socket(AF_INET, SOCK_STREAM, 0); // 创建socket
    if (sock == -1) {
        perror("无法创建socket");
        return 1;
    }
    server.sin_addr.s_addr = inet_addr("127.0.0.1"); // 设置服务器IP地址
    server.sin_family = AF_INET; // 设置为Internet协议族
    server.sin_port = htons(8888); // 设置服务器端口
    if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) { // 连接到服务器
        perror("连接失败");
        return 1;
    }

    pthread_t thread_id; // 线程ID
    if (pthread_create(&thread_id, NULL, client_recv_thread, &sock) != 0) { // 创建接收线程
        perror("创建线程失败");
        return 1;
    }

    while (1) { // 主循环,用于发送数据
        printf("输入信息: ");
        fgets(buffer, BUFFER_SIZE, stdin); // 从标准输入读取一行
        send(sock, buffer, strlen(buffer), 0); // 发送数据
    }

    close(sock); // 关闭socket
    return 0;
}
服务器代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>

#define MAX_THREADS 10
#define BUFFER_SIZE 1024

// 接收线程函数
void *server_recv_thread(void *arg) {
    int sock = *(int *)arg; // 从参数中获取socket描述符
    char buffer[BUFFER_SIZE]; // 用于接收数据的缓冲区
    while (1) {
        memset(buffer, 0, BUFFER_SIZE); // 清空缓冲区
        ssize_t bytes_received = recv(sock, buffer, BUFFER_SIZE - 1, 0); // 接收数据
        if (bytes_received <= 0) {
            perror("接收数据失败");
            break; // 如果接收失败,结束线程
        }
        printf("收到信息: %s", buffer); // 打印接收到的信息
    }
    pthread_exit(NULL); // 结束线程
}

int main() {
    int sock, client_sock; // 服务器socket描述符,客户端socket描述符
    struct sockaddr_in server, client; // 服务器和客户端地址结构
    pthread_t thread_id; // 线程ID
    sock = socket(AF_INET , SOCK_STREAM , 0); // 创建socket
    if (sock == -1) {
        perror("无法创建socket");
        return 1;
    }
    server.sin_family = AF_INET; // 设置为Internet协议族
    server.sin_addr.s_addr = INADDR_ANY; // 监听所有可用接口
    server.sin_port = htons(8888); // 设置服务器端口
    if (bind(sock, (struct sockaddr *)&server , sizeof(server)) < 0) { // 绑定socket
        perror("绑定失败");
        return 1;
    }
    listen(sock, 3); // 开始监听连接
    printf("等待接收连接...\n");
    while (1) { // 主循环,用于接受新连接
        socklen_t len = sizeof(struct sockaddr_in); // 地址长度
        client_sock = accept(sock, (struct sockaddr *)&client, &len); // 接受连接
        if (client_sock < 0) {
            perror("接受连接失败");
            return 1;
        }
        if (pthread_create(&thread_id, NULL, server_recv_thread, &client_sock) != 0) { // 创建接收线程
            perror("创建线程失败");
            return 1;
        }
    }
    close(sock); // 关闭socket
    return 0;
}

TCP建立的初衷是 1 对 1 的通信, 其本身机制无法完成并发服务器

只能借助其他方法。。。。。

这里不要求实现全双工

2. 利用多线程 或者 多进程,实现TCP服务器 可以同时跟多个客户端通信(并发服务器)

思路:

每次accept建立通信, 服务器都创建一个专属的线程任务,与客户端通信;

服务器在通信时,主要依靠的是acceptfd,每次acceptfd的值都代表不同的通信套接字;

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

#define MAX_THREADS 10 // 线程池中线程的最大数量
#define BUFFER_SIZE 1024 // 缓冲区大小

// 客户端信息结构体
typedef struct {
    int sock; // 客户端socket描述符
} client_info;

// 客户端处理线程函数
void *handle_client(void *arg) {
    client_info *info = (client_info *)arg; // 从参数中获取客户端信息
    int client_sock = info->sock; // 获取客户端socket
    char buffer[BUFFER_SIZE]; // 缓冲区,用于接收和发送数据
    
    // 循环接收并处理客户端数据
    while (1) {
        memset(buffer, 0, BUFFER_SIZE); // 清空缓冲区
        ssize_t bytes_received = recv(client_sock, buffer, BUFFER_SIZE - 1, 0); // 接收数据
        if (bytes_received <= 0) {
            printf("客户端断开连接\n");
            close(client_sock); // 如果客户端断开,关闭socket
            free(info); // 释放客户端信息结构体
            pthread_exit(NULL); // 结束线程
        } else {
            printf("接收到客户端信息: %s", buffer); // 打印接收到的信息
            send(client_sock, buffer, bytes_received, 0); // 将接收到的数据原样返回给客户端
        }
    }
}

int main() {
    int sock, client_sock; // 服务器和客户端socket描述符
    struct sockaddr_in server, client; // 服务器和客户端地址信息
    pthread_t thread_id[MAX_THREADS]; // 线程ID数组
    int active_threads = 0; // 当前线程数量

    // 创建服务器socket
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == -1) {
        perror("无法创建socket");
        return 1;
    }

    // 设置服务器地址信息
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(8888);

    // 绑定服务器地址
    if (bind(sock, (struct sockaddr *)&server, sizeof(server)) < 0) {
        perror("绑定失败");
        return 1;
    }

    // 开始监听连接
    listen(sock, 3);
    printf("等待接收连接...\n");

    // 主循环,用于接受新连接
    while (1) {
        socklen_t len = sizeof(struct sockaddr_in);
        client_sock = accept(sock, (struct sockaddr *)&client, &len);
        if (client_sock < 0) {
            perror("接受连接失败");
            continue;
        }

        // 检查线程池是否已满
        if (active_threads >= MAX_THREADS) {
            printf("线程数量已达到上限,拒绝连接\n");
            close(client_sock); // 如果线程池已满,关闭新连接的socket
            continue;
        }

        // 分配并初始化客户端信息结构体
        client_info *info = malloc(sizeof(client_info));
        info->sock = client_sock;

        // 创建线程处理新连接
        if (pthread_create(&thread_id[active_threads], NULL, handle_client, info) != 0) {
            perror("创建线程失败");
            continue;
        }

        // 增加活动线程数量
        active_threads++;
    }

    // 等待所有线程结束
    for (int i = 0; i < active_threads; i++) {
        pthread_join(thread_id[i], NULL);
    }

    // 关闭服务器socket
    close(sock);

    // 正常退出
    return 0;
}

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部