20240819套接字客户服务端通信

客户端:

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

#define BUFFER_SIZE 1024

// 全局变量声明
int sock = 0;
char buffer[BUFFER_SIZE] = { 0 };
int server_disconnected = 0;

// 函数原型声明
void* receive_messages(void* arg); // 接收消息线程函数
void send_file(const char* file_path); // 发送文件函数

int main(int argc, char* argv[])
{
    struct sockaddr_in serv_addr;

    if (argc != 3)
    {
        printf("Usage: %s <IP> <PORT>\n", argv[0]);
        return -1;
    }

    // 创建 TCP 套接字
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("Socket creation error");
        return -1;
    }

    serv_addr.sin_family = AF_INET; // 使用 IPv4 协议
    serv_addr.sin_port = htons(atoi(argv[2])); // 端口号

    // 将 IPv4 地址从文本转换为网络字节顺序
    if (inet_pton(AF_INET, argv[1], &serv_addr.sin_addr) <= 0)
    {
        perror("Invalid address/ Address not supported");
        close(sock);
        return -1;
    }

    // 连接到服务器
    if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
    {
        perror("Connection failed");
        close(sock);
        return -1;
    }

    // 创建接收消息的线程
    pthread_t recv_thread;
    if (pthread_create(&recv_thread, NULL, receive_messages, NULL) != 0)
    {
        perror("Failed to create thread");
        close(sock);
        return -1;
    }

    // 主线程负责发送数据
    while (!server_disconnected)
    {
        printf("请选择:\n");
        printf("1. 发送消息\n");
        printf("2. 发送文件\n");
        printf("3. 退出程序\n");
        printf("请输入选项: ");

        // 使用 fgets 获取输入
        char choice_str[10] = { 0 };
        if (fgets(choice_str, sizeof(choice_str), stdin) == NULL)
        {
            perror("Failed to read input");
            continue;
        }
        int choice = atoi(choice_str);

        if (server_disconnected) break;

        switch (choice)
        {
        case 1:
            while (1)
            {
                printf("请输入消息(输入exit回到菜单): ");
                if (fgets(buffer, BUFFER_SIZE, stdin) == NULL)
                {
                    perror("Failed to read message");
                    break;
                }
                if (strcmp(buffer, "exit\n") == 0)
                {
                    break;
                }
                if (send(sock, buffer, strlen(buffer), 0) <= 0)
                {
                    perror("Failed to send message");
                    break;
                }
            }
            break;
        case 2:
            printf("请输入要发送的文件路径: ");
            char file_path[BUFFER_SIZE] = { 0 };
            if (fgets(file_path, BUFFER_SIZE, stdin) == NULL)
            {
                perror("Failed to read file path");
                break;
            }
            // 去除换行符
            file_path[strcspn(file_path, "\n")] = 0;
            send_file(file_path);
            break;
        case 3:
            // 退出程序
            printf("退出程序...\n");
            close(sock);
            pthread_cancel(recv_thread); // 取消接收消息的线程
            pthread_join(recv_thread, NULL); // 等待线程结束
            return 0;
        default:
            printf("输入错误,请重新输入!\n");
            break;
        }
    }

    close(sock);
    return 0;
}

void* receive_messages(void* arg)
{
    while (1)
    {
        memset(buffer, 0, BUFFER_SIZE);
        int valread = recv(sock, buffer, BUFFER_SIZE, 0);
        if (valread > 0)
        {
            printf("Server: %s", buffer);
        }
        else if (valread == 0)
        {
            printf("Server disconnected.\n");
            server_disconnected = 1;
            break;
        }
        else
        {
            perror("Receive failed");
            server_disconnected = 1;
            break;
        }
    }
    pthread_exit(NULL);
}

void send_file(const char* file_path)
{
    FILE* file = fopen(file_path, "rb");
    if (file == NULL)
    {
        perror("Failed to open file");
        return;
    }

    // 发送文件名
    const char* file_name = strrchr(file_path, '/');
    if (file_name == NULL) {
        file_name = file_path;
    }
    else {
        file_name++; // 去掉 '/'
    }

    // 发送文件名给服务器
    if (send(sock, file_name, strlen(file_name), 0) == -1)
    {
        perror("Failed to send file name");
        fclose(file);
        return;
    }

    // 发送文件内容
    while (1)
    {
        unsigned char file_buffer[BUFFER_SIZE] = { 0 };
        size_t bytes_read = fread(file_buffer, 1, BUFFER_SIZE, file);
        if (bytes_read > 0)
        {
            if (send(sock, file_buffer, bytes_read, 0) == -1)
            {
                perror("Failed to send file data");
                break;
            }
        }

        if (bytes_read < BUFFER_SIZE)
        {
            if (feof(file))
            {
                printf("File transfer completed.\n");
            }
            if (ferror(file))
            {
                perror("Error reading from file");
            }
            break;
        }
    }

    fclose(file);
}

服务端:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define BUFFER_SIZE 1024

// 线程处理客户端连接
void* client_handler(void* arg);  // 普通消息处理线程
void* file_receive_handler(void* arg);  // 文件接收线程

int main(char argc, char* argv[])
{
    if(argc!= 2)
    {
        printf("格式错误,请指定端口号\n");
        printf("Usage: %s <port>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    int server_fd;
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    pthread_t thread_id;

    // 创建 TCP 套接字
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
    {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(atoi(argv[1]));

    // 绑定套接字到指定地址和端口
    if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0)
    {
        perror("bind failed");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    // 开始监听连接请求
    if (listen(server_fd, 3) < 0)
    {
        perror("listen");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    printf("Server listening on port %d\n", atoi(argv[1]));

    // 接受连接
    while (1)
    {
        int* new_socket_ptr = malloc(sizeof(int));
        if (new_socket_ptr == NULL)
        {
            perror("malloc failed");
            continue;
        }

        *new_socket_ptr = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
        if (*new_socket_ptr < 0)
        {
            perror("accept");
            free(new_socket_ptr);
            continue;
        }

        // 创建线程处理客户端连接
        if (pthread_create(&thread_id, NULL, client_handler, (void*)new_socket_ptr) != 0)
        {
            perror("pthread_create failed");
            close(*new_socket_ptr);
            free(new_socket_ptr);
        }
        else
        {
            pthread_detach(thread_id); // 线程分离,自动清理资源
        }
    }
    close(server_fd);
    return 0;
}

// 普通消息处理线程
void* client_handler(void* arg)
{
    int new_socket = *((int*)arg);
    char buffer[BUFFER_SIZE] = { 0 };
    const char* response = "Echo: ";

    while (1)
    {
        int valread = read(new_socket, buffer, BUFFER_SIZE);
        if (valread <= 0)
        {
            // 连接关闭或读取错误
            break;
        }
        buffer[valread] = '\0'; // 确保缓冲区以 null 终止
        printf("Received: %s\n", buffer);

        // 如果消息是文件传输请求,则启动文件接收线程
        if (strncmp(buffer, "FILE:", 5) == 0)
        {
            pthread_t file_thread_id;
            char* filename = strdup(buffer + 5); // 提取文件名
            if (pthread_create(&file_thread_id, NULL, file_receive_handler, (void*)filename) != 0)
            {
                perror("pthread_create (file_receive_handler) failed");
                free(filename);
            }
            else
            {
                pthread_detach(file_thread_id); // 文件接收线程分离
            }
        }
        else
        {
            // 发送响应
            send(new_socket, response, strlen(response), 0);
            send(new_socket, buffer, strlen(buffer), 0);
        }
        memset(buffer, 0, BUFFER_SIZE);
    }

    close(new_socket);
    free(arg); // 释放分配的内存
    pthread_exit(NULL);
}

// 文件接收线程
void* file_receive_handler(void* arg)
{
    
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值