课上测试:网络编程

发布于:2024-12-18 ⋅ 阅读:(15) ⋅ 点赞:(0)

完成下面任务(29分)

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

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

//knock.c
#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];
    char *knock_knock = "Knock, knock!\n";
    char *whos_there = "Who's there?\n";
    char *to_response = "To.\n";
    char *to_who = "To who?\n";
    char *response = "No, to you!\n";
 
    // Send initial "Knock, knock!"
    send(client_socket, knock_knock, strlen(knock_knock), 0);
 
    // Receive "Who's there?"
    memset(buffer, 0, BUFFER_SIZE);
    if (recv(client_socket, buffer, BUFFER_SIZE, 0) > 0) {
        if (strcmp(buffer, "Who's there?\n") == 0) {
            send(client_socket, to_response, strlen(to_response), 0);
        } else {
            send(client_socket, "Incorrect response. Try again.\n", strlen("Incorrect response. Try again.\n"), 0);
            close(client_socket);
            return;
        }
    }
 
    // Receive "To."
    memset(buffer, 0, BUFFER_SIZE);
    if (recv(client_socket, buffer, BUFFER_SIZE, 0) > 0) {
        if (strcmp(buffer, "To.\n") == 0) {
            send(client_socket, to_who, strlen(to_who), 0);
        } else {
            send(client_socket, "Incorrect response. Try again.\n", strlen("Incorrect response. Try again.\n"), 0);
            close(client_socket);
            return;
        }
    }
 
    // Receive "To who?"
    memset(buffer, 0, BUFFER_SIZE);
    if (recv(client_socket, buffer, BUFFER_SIZE, 0) > 0) {
        if (strcmp(buffer, "To who?\n") == 0) {
            send(client_socket, response, strlen(response), 0);
        } else {
            send(client_socket, "Incorrect response. Try again.\n", strlen("Incorrect response. Try again.\n"), 0);
        }
    }
 
    close(client_socket);
}
 
int main() {
    int server_socket, client_socket;
    struct sockaddr_in server_addr, client_addr;
    socklen_t addr_len = sizeof(client_addr);
 
    // Create socket
    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket == -1) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }
 
    // Set up server address structure
    server_addr.sin_family  = AF_INET;
    server_addr.sin_port  = htons(PORT);
    server_addr.sin_addr.s_addr  = INADDR_ANY;
 
    // Bind the socket to the address 
    if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("Bind failed");
        close(server_socket);
        exit(EXIT_FAILURE);
    }
 
    // Listen for incoming connections 
    if (listen(server_socket, 5) == -1) {
        perror("Listen failed");
        close(server_socket);
        exit(EXIT_FAILURE);
    }
 
    printf("Server listening on port %d...\n", PORT);
 
    while (1) {
        // Accept a connection
        client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &addr_len);
        if (client_socket == -1) {
            perror("Accept failed");
            continue;
        }
 
        printf("Connection accepted from %s:%d\n", inet_ntoa(client_addr.sin_addr),  ntohs(client_addr.sin_port)); 
 
        // Handle the client in a separate function
        handle_client(client_socket);
    }
 
    close(server_socket);
    return 0;
}

服务器端

root@LAPTOP-PRC71A0C:~# vim knock.c
root@LAPTOP-PRC71A0C:~# ls
GmSSL  SoftSDF-main  WPtest  bestidiocs2024  exp2  exp4  knock.c  ostest  practice  shiyan2  test  testgit  wzy
root@LAPTOP-PRC71A0C:~# gcc -o knock knock.c
root@LAPTOP-PRC71A0C:~# ./knock
Server listening on port 8080...
Connection accepted from 127.0.0.1:58032

客户端

root@LAPTOP-PRC71A0C:~# telnet localhost 8080
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Knock, knock!

root@LAPTOP-PRC71A0C:~# git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint:   git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint:   git branch -m <name>
Initialized empty Git repository in /root/.git/
root@LAPTOP-PRC71A0C:~# git add knock.c knock
root@LAPTOP-PRC71A0C:~# git commit -m "Knock knock服务器"
[master (root-commit) 45ceb8a] Knock knock服务器
 2 files changed, 107 insertions(+)
 create mode 100755 knock
 create mode 100644 knock.c

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

//knockmt.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
 
#define PORT 8080
#define BUFFER_SIZE 1024
 
typedef struct {
    int client_socket;
    pthread_t thread_id;
} ClientData;
 
void *handle_client(void *arg) {
    ClientData *client_data = (ClientData *)arg;
    int client_socket = client_data->client_socket;
    pthread_t thread_id = client_data->thread_id;
 
    char buffer[BUFFER_SIZE];
    char *knock_knock = "Knock, knock!\n";
    char *whos_there = "Who's there?\n";
    char *to_response = "To.\n";
    char *to_who = "To who?\n";
    char *response = "No, to you!\n";
 
    // Print thread ID
    printf("Thread ID: %lu handling client socket: %d\n", (unsigned long)thread_id, client_socket);
 
    // Send initial "Knock, knock!"
    send(client_socket, knock_knock, strlen(knock_knock), 0);
 
    // Receive "Who's there?"
    memset(buffer, 0, BUFFER_SIZE);
    if (recv(client_socket, buffer, BUFFER_SIZE, 0) > 0) {
        if (strcmp(buffer, "Who's there?\n") == 0) {
            send(client_socket, to_response, strlen(to_response), 0);
        } else {
            send(client_socket, "Incorrect response. Try again.\n", strlen("Incorrect response. Try again.\n"), 0);
            close(client_socket);
            free(client_data);
            return NULL;
        }
    }
 
    // Receive "To."
    memset(buffer, 0, BUFFER_SIZE);
    if (recv(client_socket, buffer, BUFFER_SIZE, 0) > 0) {
        if (strcmp(buffer, "To.\n") == 0) {
            send(client_socket, to_who, strlen(to_who), 0);
        } else {
            send(client_socket, "Incorrect response. Try again.\n", strlen("Incorrect response. Try again.\n"), 0);
            close(client_socket);
            free(client_data);
            return NULL;
        }
    }
 
    // Receive "To who?"
    memset(buffer, 0, BUFFER_SIZE);
    if (recv(client_socket, buffer, BUFFER_SIZE, 0) > 0) {
        if (strcmp(buffer, "To who?\n") == 0) {
            send(client_socket, response, strlen(response), 0);
        } else {
            send(client_socket, "Incorrect response. Try again.\n", strlen("Incorrect response. Try again.\n"), 0);
        }
    }
 
    close(client_socket);
    free(client_data);
    return NULL;
}
 
int main() {
    int server_socket, client_socket;
    struct sockaddr_in server_addr, client_addr;
    socklen_t addr_len = sizeof(client_addr);
 
    // Create socket
    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket == -1) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }
 
    // Set up server address structure 
    server_addr.sin_family  = AF_INET;
    server_addr.sin_port  = htons(PORT);
    server_addr.sin_addr.s_addr  = INADDR_ANY;
 
    // Bind the socket to the address
    if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("Bind failed");
        close(server_socket);
        exit(EXIT_FAILURE);
    }
 
    // Listen for incoming connections
    if (listen(server_socket, 5) == -1) {
        perror("Listen failed");
        close(server_socket);
        exit(EXIT_FAILURE);
    }
 
    printf("Server listening on port %d...\n", PORT);
 
    while (1) {
        // Accept a connection
        client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &addr_len);
        if (client_socket == -1) {
            perror("Accept failed");
            continue;
        }
 
        printf("Connection accepted from %s:%d\n", inet_ntoa(client_addr.sin_addr),  ntohs(client_addr.sin_port)); 
 
        // Create client data structure
        ClientData *client_data = (ClientData *)malloc(sizeof(ClientData));
        client_data->client_socket = client_socket;
        client_data->thread_id = 0;
 
        // Create a new thread to handle the client
        pthread_t thread_id;
        if (pthread_create(&thread_id, NULL, handle_client, client_data) != 0) {
            perror("Thread creation failed");
            close(client_socket);
            free(client_data);
            continue;
        }
 
        // Store the thread ID in the client data
        client_data->thread_id = thread_id;
    }
 
    close(server_socket);
    return 0;
}

服务器端

root@LAPTOP-PRC71A0C:~# vim knockmt.c
root@LAPTOP-PRC71A0C:~# gcc -o knockmt knockmt.c -lpthread
root@LAPTOP-PRC71A0C:~# ./knockmt
Server listening on port 8080...
Connection accepted from 127.0.0.1:49937
Thread ID: 139957183972928 handling client socket: 4
Connection accepted from 127.0.0.1:49942
Thread ID: 139957175518784 handling client socket: 5

客户端1

root@LAPTOP-PRC71A0C:~# telnet localhost 8080
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Knock, knock!

客户端2

root@LAPTOP-PRC71A0C:~# nc localhost 8080
Knock, knock!

root@LAPTOP-PRC71A0C:~# git add knockmt.c knockmt
root@LAPTOP-PRC71A0C:~# git commit -m "knock knock服务器多线程实现"
[master 275f3b8] knock knock服务器多线程实现
 2 files changed, 138 insertions(+)
 create mode 100755 knockmt
 create mode 100644 knockmt.c

4 提交git log结果(3分)

root@LAPTOP-PRC71A0C:~# git log
Author: 魏正一 <11565599+wei-zhengyi@user.noreply.gitee.com>
Date:   Tue Dec 17 10:57:54 2024 +0800

    knock knock服务器多线程实现

commit 45ceb8a965795fd7b193b748d9c7ecaa1df3787b
Author: 魏正一 <11565599+wei-zhengyi@user.noreply.gitee.com>
Date:   Tue Dec 17 10:48:51 2024 +0800

    Knock knock服务器

提交要求 (1’)

1 记录实践过程和 AI 问答过程,尽量不要截图,给出文本内容
2 (选做)推荐所有作业托管到 gitee或 github 上
3 (必做)提交作业 markdown文档,命名为“学号-姓名-作业题目.md”
4 (必做)提交作业 markdown文档转成的 PDF 文件,命名为“学号-姓名-作业题目.pdf”