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