20221320—冯泰瑞—课上测试:网络编程

20221320—冯泰瑞—课上测试:网络编程

完成下面任务(29分)

1.在 Ubuntu 或 openEuler 中完成任务(推荐openEuler)

2.参考《head first C》实现knock knock服务器,提交代码knock.c,编译运行过程(13分)

服务器

fengtairui@fengtairui-virtual-machine:~$ touch knock.c
fengtairui@fengtairui-virtual-machine:~$ vim knock.c
fengtairui@fengtairui-virtual-machine:~$ gcc -o knock knock.c
fengtairui@fengtairui-virtual-machine:~$ ./knock
Knock Knock server is running on port 8080...

客户端

fengtairui@fengtairui-virtual-machine:~$ telnet localhost 8080
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Knock! Knock!
Who's there?
Lettuce.
Lettuce who?
Lettuce in, it's cold out here!

代码

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

#define PORT 8080
#define BUFFER_SIZE 1024

void handle_client(int client_socket) {
    char buffer[BUFFER_SIZE];
    int read_size;

    // 发送初始消息
    send(client_socket, "Knock! Knock!\n", strlen("Knock! Knock!\n"), 0);
    
    // 等待客户端的响应
    read_size = recv(client_socket, buffer, BUFFER_SIZE, 0);
    buffer[read_size] = '\0'; // 确保字符串以 null 结尾

    if (strcmp(buffer, "Who's there?\n") == 0) {
        send(client_socket, "Lettuce.\n", strlen("Lettuce.\n"), 0);
        read_size = recv(client_socket, buffer, BUFFER_SIZE, 0);
        buffer[read_size] = '\0';

        if (strcmp(buffer, "Lettuce who?\n") == 0) {
            send(client_socket, "Lettuce in, it's cold out here!\n", strlen("Lettuce in, it's cold out here!\n"), 0);
        } else {
            send(client_socket, "I didn't get that.\n", strlen("I didn't get that.\n"), 0);
        }
    } else {
        send(client_socket, "I didn't get that.\n", strlen("I didn't get that.\n"), 0);
    }

    close(client_socket);
}

int main() {
    int server_socket, client_socket;
    struct sockaddr_in server_addr, client_addr;
    socklen_t addr_size;

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

    // 配置服务器地址
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);

    // 绑定 socket
    if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("Bind failed");
        close(server_socket);
        exit(EXIT_FAILURE);
    }

    // 监听连接
    if (listen(server_socket, 5) < 0) {
        perror("Listen failed");
        close(server_socket);
        exit(EXIT_FAILURE);
    }

    printf("Knock Knock server is running on port %d...\n", PORT);

    // 接受客户端连接
    while (1) {
        addr_size = sizeof(client_addr);
        client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &addr_size);
        if (client_socket < 0) {
            perror("Accept failed");
            continue;
        }

        // 处理客户端
        handle_client(client_socket);
    }

    // 关闭服务器 socket
    close(server_socket);
    return 0;
}

3.使用多线程实现knock knock服务器,提交代码knockmt.c,编译运行过程,至少两个客户端测试,服务器运行结果中要打印线程id(13分)

服务器

fengtairui@fengairui-virtual-machine:~$ touch knockmt.c
fengtairui@fengtairui-virtual-machine:~$ vim knockmt.c
fengtairui@fengtairui-virtual-machine:~$ gcc knockmt.c -o knockmt -lpthread
fengtairui@fengtairui-virtual-machine:~$ ./knockmt
Knock knock server is listening on port 8088...
Accepted connection from 127.0.0.1:55206
Thread ID: 123637524858432 is handling client connection
Accepted connection from 127.0.0.1:57026
Thread ID: 123637514372672 is handling client connection

客户端1

fengtairui@fengtairui-virtual-machine:~$ telnet localhost 8088
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Knock knock
Who's there?
Omar
Omar who?
Omar my goodness, you scared me!
Haha, that's a good one! Come on in.

客户端2

fengtairui@fengtairui-virtual-machine:~$ telnet localhost 8088
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Knock
You didn't say 'Knock knock'. Goodbye.

代码

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

#define PORT 8088
#define MAX_BUFFER_SIZE 1024

// 结构体用于传递参数给线程函数
typedef struct {
    int clientSocket;
    struct sockaddr_in clientAddr;
} ThreadArgs;

// 处理客户端连接的线程函数
void *handleClientThread(void *arg) {
    ThreadArgs *args = (ThreadArgs *)arg;
    int clientSocket = args->clientSocket;
    struct sockaddr_in clientAddr = args->clientAddr;
    char buffer[MAX_BUFFER_SIZE];
    int n;

    // 获取线程ID
    pthread_t tid = pthread_self();
    printf("Thread ID: %lu is handling client connection\n", tid);

    // 接收客户端消息
    n = read(clientSocket, buffer, MAX_BUFFER_SIZE);
    if (n < 0) {
        perror("Error reading from socket");
        close(clientSocket);
        free(arg);
        pthread_exit(NULL);
    }
    buffer[n] = '\0';

    // 检查消息是否为"Knock knock"
    if (strcmp(buffer, "Knock knock") == 0) {
        const char *response1 = "Who's there?";
        write(clientSocket, response1, strlen(response1));

        // 接收客户端下一条消息
        n = read(clientSocket, buffer, MAX_BUFFER_SIZE);
        if (n < 0) {
            perror("Error reading from socket");
            close(clientSocket);
            free(arg);
            pthread_exit(NULL);
        }
        buffer[n] = '\0';

        // 检查消息是否为"Omar"
        if (strcmp(buffer, "Omar") == 0) {
            const char *response2 = "Omar who?";
            write(clientSocket, response2, strlen(response2));

            // 接收客户端最后一条消息
            n = read(clientSocket, buffer, MAX_BUFFER_SIZE);
            if (n < 0) {
                perror("Error reading from socket");
                close(clientSocket);
                free(arg);
                pthread_exit(NULL);
            }
            buffer[n] = '\0';

            // 检查消息是否为"Omar my goodness, you scared me!"
            if (strcmp(buffer, "Omar my goodness, you scared me!") == 0) {
                const char *response3 = "Haha, that's a good one! Come on in.";
                write(clientSocket, response3, strlen(response3));
            } else {
                const char *response3 = "I don't understand. Goodbye.";
                write(clientSocket, response3, strlen(response3));
            }
        } else {
            const char *response2 = "I don't know who that is. Goodbye.";
            write(clientSocket, response2, strlen(response2));
        }
    } else {
        const char *response = "You didn't say 'Knock knock'. Goodbye.";
        write(clientSocket, response, strlen(response));
    }

    close(clientSocket);
    free(arg);
    pthread_exit(NULL);
}

int main() {
    int serverSocket, clientSocket;
    struct sockaddr_in serverAddr, clientAddr;
    socklen_t clientAddrLen = sizeof(clientAddr);
    pthread_t thread;

    // 创建套接字
    serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket < 0) {
        perror("Error creating socket");
        exit(1);
    }

    // 初始化服务器地址结构
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(PORT);

    // 绑定套接字到指定地址和端口
    if (bind(serverSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
        perror("Error binding socket");
        exit(1);
    }

    // 监听连接请求
    if (listen(serverSocket, 5) < 0) {
        perror("Error listening for connections");
        exit(1);
    }

    printf("Knock knock server is listening on port %d...\n", PORT);

    while (1) {
        // 接受客户端连接
        clientSocket = accept(serverSocket, (struct sockaddr *)&clientAddr, &clientAddrLen);
        if (clientSocket < 0) {
            perror("Error accepting connection");
            continue;
        }

        // 获取客户端IP地址
        char clientIP[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, INET_ADDRSTRLEN);
        printf("Accepted connection from %s:%d\n", clientIP, ntohs(clientAddr.sin_port));

        // 为每个客户端连接创建一个新线程
        ThreadArgs *args = (ThreadArgs *)malloc(sizeof(ThreadArgs));
        args->clientSocket = clientSocket;
        args->clientAddr = clientAddr;
        if (pthread_create(&thread, NULL, handleClientThread, (void *)args)!= 0) {
            perror("Error creating thread");
            close(clientSocket);
            free(args);
            continue;
        }

        // 分离线程,使其在结束后自动释放资源
        pthread_detach(thread);
    }

    close(serverSocket);

    return 0;
}

4.提交git log结果(3分)

fengtairui@fengtairui-virtual-machine:~$ git add knock.c knockmt.c knock knockmt
fengtairui@fengtairui-virtual-machine:~$ git commit -m "konck"
[master 0027bef] konck
 4 files changed, 220 insertions(+)
 create mode 100755 knock
 create mode 100644 knock.c
 create mode 100755 knockmt
 create mode 100644 knockmt.c
fengtairui@fengtairui-virtual-machine:~$ git log
commit 0027bef181c7570899f2918eb52ed4f8cbc6041c (HEAD -> master)
Author: fengtairui <1978274655@qq.com>
Date:   Tue Dec 17 10:58:53 2024 +0800

    konck
posted @ 2025-02-02 20:14  20221320冯泰瑞  阅读(18)  评论(0)    收藏  举报