文章目录
完成下面任务(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”