1. 程式人生 > >實驗樓樓賽第4期C語言專案挑戰題 -遠端 Shell

實驗樓樓賽第4期C語言專案挑戰題 -遠端 Shell

這道題實際上考察的是 Linux 上的 C 語言網路程式設計。並且只給出了客戶端的原始碼和服務端的二進位制檔案。需要根據客戶端程式碼編譯和執行的狀態來找 bug,必要的時候需要進行除錯跟蹤。

在客戶端程式碼檔案中包含了多個 socket 程式設計中容易犯的錯誤:

錯誤1:TCP 連線

伺服器端使用 TCP 連線,程式碼中建立 socket 的時候用的是 UDP 連線方式,需要使用:

int sock = socket(AF_INET, SOCK_STREAM, 0);

錯誤2:埠號使用網路位元組序

位元組序使用錯誤也是常見的 socket 錯誤,需要使用 htons 函式將主機位元組序的埠號改為網路位元組序:

connection.sin_port = htons(PORT);

錯誤3:強制型別轉化

connect 函式中第二個引數需要使用 struct sockaddr 型別指標,但 connection 的型別不匹配,這個錯誤在編譯的提示中可以很容易看出來。修改的程式碼為:

if (connect(sock, (struct sockaddr*)&connection, sizeof(connection)) != 0)

錯誤4:if 中的 == 誤用

pid 變數沒有初始化直接在 if 中用作 == 比較,此處應該是 =,pid 為 fork 建立後返回的程序 ID:

if(pid = fork())

最終修改後的程式碼:

#include "share.h"

void send_cmd(int sock, int pid) {
	char str[MAX_MSG_LENGTH] = {0};
	printf("> ");
	while (fgets(str, MAX_MSG_LENGTH, stdin) == str) {
		if(strncmp(str, END_STRING, strlen(END_STRING)) == 0) break;
		if(send(sock, str, strlen(str)+1, 0) < 0) perro("send");
	}
	kill(pid, SIGKILL);
	printf("Goodbye.\n");
}

void receive(int sock) {
	char buf[MAX_MSG_LENGTH] = {0};
	int filled = 0;	
	
    while(filled = recv(sock, buf, MAX_MSG_LENGTH-1, 0)){
		buf[filled] = '\0';
		printf("%s", buf);
		fflush(stdout);		
	}	
	printf("Server disconnected.\n");
}

int main(int argc, char **argv) {
	if(argc != 2) perro("args");

	int sock = socket(AF_INET, SOCK_STREAM, 0);
	if(sock == -1) perro("socket");

	struct in_addr server_addr;
	if(!inet_aton(argv[1], &server_addr)) perro("inet_aton");

	struct sockaddr_in connection;
	connection.sin_family = AF_INET;
	memcpy(&connection.sin_addr, &server_addr, sizeof(server_addr));
	connection.sin_port = htons(PORT);
	if (connect(sock, (struct sockaddr*)&connection, sizeof(connection)) != 0) perro("connect");
	
	int pid;	
	if(pid = fork()) send_cmd(sock, pid);
	else receive(sock);
	
	return 0;
}