jelasin 的學生作業:
#include
#include
#include
#include
#include
#include
#include
#include
#define SERVER_PORT 8080
#define BACKLOG 10
#define BUFFER_SIZE 1024
// 客戶端信息結構體
typedef struct {
int client_socket;
struct sockaddr_in client_addr;
} client_info_t;
// 線程處理函數:處理單個客戶端連接
void* handle_client(void* arg) {
client_info_t* client_info = (client_info_t*)arg;
int client_socket = client_info->client_socket;
struct sockaddr_in client_addr = client_info->client_addr;
printf("[線程 %ld] 開始處理客戶端: %s:%d\n",
pthread_self(),
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
char buffer[BUFFER_SIZE];
ssize_t bytes_received;
// 與客戶端通信循環
while (1) {
bytes_received = recv(client_socket, buffer, BUFFER_SIZE - 1, 0);
if (bytes_received > 0) {
buffer[bytes_received] = '\0';
printf("[線程 %ld] 收到消息: %s", pthread_self(), buffer);
// 簡單回顯 - 增加響應緩沖區大小以避免截斷警告
char response[BUFFER_SIZE + 64]; // 為格式化字符串預留額外空間
snprintf(response, sizeof(response), "[線程 %ld] Echo: %s", pthread_self(), buffer);
send(client_socket, response, strlen(response), 0);
} else if (bytes_received == 0) {
printf("[線程 %ld] 客戶端斷開連接: %s:%d\n",
pthread_self(),
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
break;
} else {
perror("recv失敗");
break;
}
}
close(client_socket);
free(client_info);
printf("[線程 %ld] 客戶端處理完成,線程退出\n", pthread_self());
pthread_exit(NULL);
}
// 函數:創建和綁定服務器socket
int create_and_bind_server(const char* ip, int port) {
int server_socket;
struct sockaddr_in server_addr;
int reuse = 1;
// 1. 創建套接字
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
perror("socket創建失敗");
return -1;
}
printf("Socket創建成功 (fd: %d)\n", server_socket);
// 設置SO_REUSEADDR選項
if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
perror("setsockopt失敗");
close(server_socket);
return -1;
}
// 2. 配置服務器地址結構
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
// 根據IP參數設置綁定地址
if (ip == NULL || strcmp(ip, "0.0.0.0") == 0) {
server_addr.sin_addr.s_addr = INADDR_ANY; // 綁定到所有可用接口
printf("配置為監聽所有接口 (0.0.0.0:%d)\n", port);
} else {
if (inet_aton(ip, &server_addr.sin_addr) == 0) {
printf("無效的IP地址: %s\n", ip);
close(server_socket);
return -1;
}
printf("配置為監聽指定IP (%s:%d)\n", ip, port);
}
// 3. 綁定IP地址和端口號
if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
perror("bind失敗");
close(server_socket);
return -1;
}
printf("成功綁定到端口 %d\n", port);
return server_socket;
}
int main(int argc, char *argv[]) {
int server_socket;
// 解析命令行參數
char *server_ip = NULL;
int server_port = SERVER_PORT;
if (argc >= 2) {
server_port = atoi(argv[1]);
if (server_port 65535) {
printf("無效端口號: %s\n", argv[1]);
exit(EXIT_FAILURE);
}
}
if (argc >= 3) {
server_ip = argv[2];
}
// 創建和綁定服務器socket
server_socket = create_and_bind_server(server_ip, server_port);
if (server_socket == -1) {
exit(EXIT_FAILURE);
}
// 4. 開始監聽
if (listen(server_socket, BACKLOG) == -1) {
perror("listen失敗");
close(server_socket);
exit(EXIT_FAILURE);
}
printf("服務器開始監聽,等待客戶端連接...\n");
printf("監聽隊列大小: %d (最多可同時等待 %d 個連接)\n", BACKLOG, BACKLOG);
printf("服務器地址: %s:%d\n", server_ip ? server_ip : "0.0.0.0", server_port);
// 5. 主循環:接受客戶端連接
while (1) {
printf("\n等待新的客戶端連接...\n");
// 接受客戶端連接
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_addr_len);
if (client_socket == -1) {
perror("accept失敗");
continue;
}
printf("客戶端連接成功: %s:%d (socket fd: %d)\n",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port),
client_socket);
// 創建結構體保存客戶端信息
client_info_t* client_info = (client_info_t*)malloc(sizeof(client_info_t));
if (client_info == NULL) {
perror("malloc失敗");
close(client_socket);
continue;
}
client_info->client_socket = client_socket;
client_info->client_addr = client_addr;
// 創建線程處理客戶端連接
pthread_t tid;
if (pthread_create(&tid, NULL, handle_client, client_info) != 0) {
perror("pthread_create失敗");
close(client_socket);
free(client_info);
} else {
// 分離線程,在線程結束時自動回收資源
pthread_detach(tid);
printf("為客戶端 %s:%d 創建處理線程 %ld\n",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port),
tid);
}
}
close(server_socket);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 8080
#define BUFFER_SIZE 1024
int main() {
int client_socket;
struct sockaddr_in server_addr;
char buffer[BUFFER_SIZE];
ssize_t bytes_received;
// 創建套接字
client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket == -1) {
perror("socket創建失敗");
exit(EXIT_FAILURE);
}
// 配置服務器地址結構
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
// 連接到服務器
if (connect(client_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
perror("連接服務器失敗");
close(client_socket);
exit(EXIT_FAILURE);
}
printf("成功連接到服務器 %s:%d\n", SERVER_IP, SERVER_PORT);
printf("輸入消息發送到服務器 (輸入'quit'退出):\n");
while (1) {
// 從用戶獲取輸入
printf("客戶端> ");
fflush(stdout);
if (fgets(buffer, BUFFER_SIZE, stdin) == NULL) {
break;
}
// 檢查退出條件
if (strncmp(buffer, "quit", 4) == 0) {
printf("客戶端退出...\n");
break;
}
// 發送消息到服務器
ssize_t bytes_sent = send(client_socket, buffer, strlen(buffer), 0);
if (bytes_sent == -1) {
perror("發送消息失敗");
break;
}
// 接收服務器響應
bytes_received = recv(client_socket, buffer, BUFFER_SIZE - 1, 0);
if (bytes_received > 0) {
buffer[bytes_received] = '\0';
// 移除消息末尾的換行符(如果有的話)
char *newline = strchr(buffer, '\n');
if (newline) *newline = '\0';
printf("服務器響應: %s\n", buffer);
} else if (bytes_received == 0) {
printf("服務器關閉了連接\n");
break;
} else {
perror("接收消息失敗");
break;
}
}
// 關閉套接字
close(client_socket);
return 0;
}