浪潮君 的學(xué)生作業(yè):
服務(wù)端
#include // 標(biāo)準(zhǔn)輸入輸出頭文件,包含 printf、perror 等
#include // 包含 exit、malloc 等函數(shù)
#include // 包含字符串處理函數(shù),如 memset、strlen
#include // 包含 close、read、write 等 Unix/Linux 系統(tǒng)調(diào)用
#include // 包含 IP 地址轉(zhuǎn)換函數(shù),如 inet_ntop、htons
#include // 包含 socket 函數(shù)與結(jié)構(gòu)體定義
#define SERVER_PORT 8890 // 服務(wù)端監(jiān)聽的端口號
#define BACKLOG 5 // 最大連接請求隊列長度
#define BUFFER_SIZE 1024 // 緩沖區(qū)最大長度(接收/發(fā)送)
// 創(chuàng)建 TCP 服務(wù)器監(jiān)聽 socket,并綁定指定 IP 和端口
int tcp_socket_create(const char *ip, int port, int backlog) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 創(chuàng)建 IPv4、TCP 套接字
if (sockfd < 0) {
perror("socket failed"); // 創(chuàng)建失敗時輸出錯誤信息
return -1;
}
// 設(shè)置 socket 地址重用選項,防止 bind 報錯 "Address already in use"
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr)); // 初始化結(jié)構(gòu)體為 0
addr.sin_family = AF_INET; // 設(shè)置地址族為 IPv4
addr.sin_addr.s_addr = INADDR_ANY; // 監(jiān)聽所有本地 IP 地址(0.0.0.0)
addr.sin_port = htons(SERVER_PORT); // 設(shè)置監(jiān)聽端口,使用網(wǎng)絡(luò)字節(jié)序
// 綁定 socket 到本地地址與端口
if (bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("bind failed"); // 綁定失敗
close(sockfd);
return -1;
}
// 啟動監(jiān)聽,將 socket 設(shè)為被動連接模式
if (listen(sockfd, backlog) < 0) {
perror("listen failed"); // 監(jiān)聽失敗
close(sockfd);
return -1;
}
return sockfd; // 返回監(jiān)聽套接字
}
// 處理每個客戶端連接的函數(shù)
void handle_client(int conn_fd, struct sockaddr_in *client_addr) {
char buffer[BUFFER_SIZE]; // 接收客戶端消息的緩沖區(qū)
char client_ip[INET_ADDRSTRLEN]; // 存儲客戶端 IP 字符串
// 將客戶端 IP 地址轉(zhuǎn)換為可讀字符串格式
inet_ntop(AF_INET, &client_addr->sin_addr, client_ip, sizeof(client_ip));
// 將端口號從網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換為主機(jī)字節(jié)序
int client_port = ntohs(client_addr->sin_port);
printf("客戶端已連接:%s:%d\n", client_ip, client_port);
// 循環(huán)接收客戶端消息并回顯
while (1) {
// 接收客戶端消息
ssize_t len = recv(conn_fd, buffer, sizeof(buffer) - 1, 0);
if (len < 0) {
printf("客戶端斷開連接\n"); // 接收失敗
break;
}
buffer[len] = '\0'; // 添加字符串結(jié)束符,構(gòu)成合法 C 字符串
printf("收到消息:%s\n", buffer);
// 構(gòu)造服務(wù)端回顯響應(yīng)內(nèi)容
char reply[BUFFER_SIZE];
snprintf(reply, sizeof(reply), "服務(wù)端已收到: %s", buffer);
// 將回應(yīng)內(nèi)容發(fā)回客戶端
send(conn_fd, reply, strlen(reply), 0);
}
// 關(guān)閉客戶端連接 socket
close(conn_fd);
}
// 主函數(shù):程序入口
int main(int argc, char *argv[]) {
// 創(chuàng)建監(jiān)聽 socket,并綁定本地端口
int listen_fd = tcp_socket_create("0.0.0.0", SERVER_PORT, BACKLOG);
if (listen_fd < 0) {
fprintf(stderr, "監(jiān)聽 socket 創(chuàng)建失敗。退出\n");
return -1;
}
printf("服務(wù)端啟動,監(jiān)聽端口 %d\n", SERVER_PORT);
// 主循環(huán):接收并處理客戶端連接
while (1) {
struct sockaddr_in client_addr; // 用于存儲客戶端地址信息
socklen_t client_len = sizeof(client_addr);
// 接受客戶端連接請求,阻塞等待連接
int conn_fd = accept(listen_fd, (struct sockaddr *) &client_addr, &client_len);
if (conn_fd < 0) {
perror("accept failed"); // 接收失敗
continue;
}
// 處理客戶端連接
handle_client(conn_fd, &client_addr);
}
// 關(guān)閉監(jiān)聽 socket
close(listen_fd);
return 0;
}
客戶端
#include // 標(biāo)準(zhǔn)輸入輸出,如 printf、fprintf
#include // 包含 exit 函數(shù)
#include // 字符串處理,如 strlen、strcspn
#include // 包含 close 函數(shù)
#include // 網(wǎng)絡(luò)地址轉(zhuǎn)換函數(shù),如 inet_pton
#include // socket API 函數(shù)
#define SERVER_IP "127.0.0.1" // 服務(wù)器 IP 地址(本地環(huán)回地址)
#define SERVER_PORT 8890 // 服務(wù)器端口號(需與服務(wù)端保持一致)
#define BUFFER_SIZE 1024 // 緩沖區(qū)最大長度
// 創(chuàng)建 TCP 客戶端 socket 并連接服務(wù)器
int tcp_client_connect(const char *ip, int port) {
// 創(chuàng)建 socket(IPv4 + TCP)
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket 創(chuàng)建失敗");
return -1;
}
// 配置服務(wù)器地址結(jié)構(gòu)
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr)); // 清零初始化
server_addr.sin_family = AF_INET; // IPv4
server_addr.sin_port = htons(port); // 設(shè)置端口(轉(zhuǎn)為網(wǎng)絡(luò)字節(jié)序)
// 將 IP 字符串轉(zhuǎn)換為二進(jìn)制形式
if (inet_pton(AF_INET, ip, &server_addr.sin_addr)