gcc -Wall -o server -lpthread server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAX_CLIENTS 5
#define BUF_SIZE 1024
int client_fds[MAX_CLIENTS]; // 客戶端 socket 數組
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; // 保護數組
void *handle_client(void *arg) {
int fd = *(int *)arg;
char name[32], buf[BUF_SIZE], msg[BUF_SIZE + 32];
int n;
// 1. 接收用戶名
n = recv(fd, name, sizeof(name) - 1, 0);
if (n <= 0) goto cleanup;
name[n] = '\0';
// 2. 廣播上線通知
snprintf(msg, sizeof(msg), "[%s 加入聊天室]\n", name);
broadcast(msg, fd);
// 3. 消息循環
while ((n = recv(fd, buf, BUF_SIZE - 1, 0)) > 0) {
buf[n] = '\0';
snprintf(msg, sizeof(msg), "%s: %s", name, buf);
broadcast(msg, fd);
}
// 4. 下線廣播
snprintf(msg, sizeof(msg), "[%s 退出聊天室]\n", name);
broadcast(msg, fd);
cleanup:
close(fd);
pthread_mutex_lock(&lock);
for (int i = 0; i < MAX_CLIENTS; ++i)
if (client_fds[i] == fd) { client_fds[i] = -1; break; }
pthread_mutex_unlock(&lock);
return NULL;
}
void broadcast(const char *msg, int sender_fd) {
pthread_mutex_lock(&lock);
for (int i = 0; i < MAX_CLIENTS; ++i) {
if (client_fds[i] != -1 && client_fds[i] != sender_fd)
send(client_fds[i], msg, strlen(msg), 0);
}
pthread_mutex_unlock(&lock);
}
int main() {
for (int i = 0; i < MAX_CLIENTS; ++i) client_fds[i] = -1;
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
addr.sin_addr.s_addr = INADDR_ANY;
bind(server_fd, (struct sockaddr *)&addr, sizeof(addr));
listen(server_fd, 10);
printf("Server listening on port 12345...\n");
while (1) {
struct sockaddr_in cli_addr;
socklen_t len = sizeof(cli_addr);
int fd = accept(server_fd, (struct sockaddr *)&cli_addr, &len);
if (fd < 0) continue;
// 找空位
pthread_mutex_lock(&lock);
int idx = -1;
for (int i = 0; i < MAX_CLIENTS; ++i)
if (client_fds[i] == -1) { idx = i; break; }
if (idx == -1) { close(fd); pthread_mutex_unlock(&lock); continue; }
client_fds[idx] = fd;
pthread_mutex_unlock(&lock);
pthread_t tid;
pthread_create(&tid, NULL, handle_client, &fd);
pthread_detach(tid); // 自動回收資源
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define BUF_SIZE 1024
void *recv_thread(void *arg) {
int fd = *(int *)arg;
char buf[BUF_SIZE];
int n;
while ((n = recv(fd, buf, BUF_SIZE - 1, 0)) > 0) {
buf[n] = '\0';
printf("%s", buf);
fflush(stdout);
}
return NULL;
}
int main(int argc, char *argv[]) {
if (argc != 3) { printf("Usage: %s \n", argv[0]); return 1; }
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[2]));
inet_pton(AF_INET, argv[1], &addr.sin_addr);
connect(fd, (struct sockaddr *)&addr, sizeof(addr));
// 發送用戶名
char name[32];
printf("輸入用戶名: "); fgets(name, sizeof(name), stdin);
name[strcspn(name, "\n")] = '\0';
send(fd, name, strlen(name), 0);
pthread_t tid;
pthread_create(&tid, NULL, recv_thread, &fd);
pthread_detach(tid);
// 主線程發送消息
char buf[BUF_SIZE];
while (fgets(buf, BUF_SIZE, stdin)) {
send(fd, buf, strlen(buf), 0);
}
close(fd);
return 0;
}
client_fds 共享數組需互斥鎖保護pthread_detach 避免殭屍線程recv 返回長度,手動添加 \0 才能作為 C 字符串處理-lpthread 必須放在源文件後epoll (Linux) / IOCP (Windows) 支持萬級連接這個迷你聊天室雖簡單,但包含Socket 編程、多線程同步、網絡字節序、資源管理等系統級開發核心技能。從這裡出發,逐步替換為生產級組件,即可構建高性能網絡服務。