#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>
#define MAX_CLIENTS 2 // 最大客户端连接数
#define BUFFER_SIZE 1024 // 消息缓冲区大小
int main(int argc, char *argv[]) {
/* 参数校验 */
if (argc != 2) {
printf("用法: %s <端口号>\n", argv[0]);
exit(1);
}
/* 创建服务器socket */
// AF_INET: IPv4协议
// SOCK_STREAM: 流式socket(TCP)
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("socket创建失败");
exit(1);
}
/* 配置服务器地址 */
struct sockaddr_in addr = {
.sin_family = AF_INET, // IPv4地址族
.sin_port = htons(atoi(argv[1])), // 端口号(主机字节序转网络字节序)
.sin_addr.s_addr = INADDR_ANY // 监听所有本地接口
};
/* 绑定socket到指定地址 */
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) {
perror("绑定失败");
close(server_fd);
exit(1);
}
/* 开始监听连接请求 */
// 参数5: 等待连接队列的最大长度
if (listen(server_fd, 5) < 0) {
perror("监听失败");
close(server_fd);
exit(1);
}
printf("服务器已启动,监听端口: %s\n", argv[1]);
/* 客户端管理数据结构 */
int client_sockets[MAX_CLIENTS] = {0}; // 客户端socket数组
char client_ids[MAX_CLIENTS] = {0}; // 客户端标识符('1'或'2')
fd_set readfds; // 文件描述符集合
int max_fd; // 最大文件描述符值
/* 主事件循环 */
while(1) {
// 清空文件描述符集合
FD_ZERO(&readfds);
// 添加服务器socket到监听集合
FD_SET(server_fd, &readfds);
max_fd = server_fd;
// 添加客户端socket到监听集合
for(int i = 0; i < MAX_CLIENTS; i++) {
if(client_sockets[i] > 0) {
FD_SET(client_sockets[i], &readfds);
if(client_sockets[i] > max_fd)
max_fd = client_sockets[i];
}
}
/* 使用select监听IO事件 */
// 参数说明:
// 1. max_fd+1: 最大文件描述符值+1
// 2. &readfds: 读事件监听集合
// 3. NULL: 不监听写事件
// 4. NULL: 不监听异常事件
// 5. NULL: 无限等待
int activity = select(max_fd + 1, &readfds, NULL, NULL, NULL);
if ((activity < 0) && (errno != EINTR)) {
perror("select错误");
}
/* 处理新连接请求 */
if (FD_ISSET(server_fd, &readfds)) {
// 接受新连接
int new_socket = accept(server_fd, NULL, NULL);
if (new_socket < 0) {
perror("接受连接失败");
continue;
}
// 将新客户端添加到数组
int added = 0;
for(int i = 0; i < MAX_CLIENTS; i++) {
if(client_sockets[i] == 0) {
client_sockets[i] = new_socket;
// 接收客户端标识符(阻塞式接收第一个字节)
recv(new_socket, &client_ids[i], 1, 0);
printf("客户端 %c 已连接\n", client_ids[i]);
added = 1;
break;
}
}
if (!added) {
printf("连接已满,拒绝新连接\n");
close(new_socket);
}
}
/* 处理客户端消息 */
for(int i = 0; i < MAX_CLIENTS; i++) {
int sd = client_sockets[i];
if (sd > 0 && FD_ISSET(sd, &readfds)) {
char buffer[BUFFER_SIZE] = {0};
// 接收消息
int valread = read(sd, buffer, BUFFER_SIZE);
/* 处理断开连接 */
if (valread == 0) {
getpeername(sd, (struct sockaddr*)&addr, (socklen_t*)&addr);
printf("客户端 %c 断开连接\n", client_ids[i]);
close(sd);
client_sockets[i] = 0;
client_ids[i] = 0;
}
/* 转发消息 */
else {
printf("转发来自客户端 %c 的消息\n", client_ids[i]);
// 遍历所有客户端进行转发
for(int j = 0; j < MAX_CLIENTS; j++) {
int dest = client_sockets[j];
// 跳过自身和无效socket
if (dest > 0 && client_ids[j] != client_ids[i]) {
send(dest, buffer, strlen(buffer), 0);
}
}
}
}
}
}
close(server_fd);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <poll.h>
#define BUFFER_SIZE 1024 // 输入缓冲区大小
int main(int argc, char *argv[]) {
/* 参数校验 */
if (argc != 3) {
printf("用法: %s <IP地址> <端口号>\n", argv[0]);
exit(1);
}
/* 创建客户端socket */
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket创建失败");
exit(1);
}
/* 配置服务器地址 */
struct sockaddr_in serv_addr = {
.sin_family = AF_INET,
.sin_port = htons(atoi(argv[2])), // 端口号转换
.sin_addr.s_addr = inet_addr(argv[1]) // IP地址转换
};
/* 建立连接 */
if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("连接失败");
close(sock);
exit(1);
}
/* 发送客户端标识符 */
char client_id = '1';
send(sock, &client_id, 1, 0);
printf("已连接到服务器\n");
/* 配置poll监听结构体 */
struct pollfd fds[2] = {
{.fd = STDIN_FILENO, .events = POLLIN}, // 监听标准输入
{.fd = sock, .events = POLLIN} // 监听socket输入
};
/* 主循环 */
while(1) {
// 使用poll等待事件(无限等待)
int ret = poll(fds, 2, -1);
if (ret == -1) {
perror("poll错误");
break;
}
/* 处理键盘输入事件 */
if (fds[0].revents & POLLIN) {
char buffer[BUFFER_SIZE];
// 安全获取输入(自动截断)
if (fgets(buffer, BUFFER_SIZE, stdin) != NULL) {
// 发送消息到服务器
send(sock, buffer, strlen(buffer), 0);
}
}
/* 处理服务器消息事件 */
if (fds[1].revents & POLLIN) {
char buffer[BUFFER_SIZE] = {0};
int len = recv(sock, buffer, BUFFER_SIZE, 0);
if (len > 0) {
printf("收到消息: %s", buffer);
} else if (len == 0) {
printf("服务器断开连接\n");
break;
} else {
perror("接收错误");
break;
}
}
}
close(sock);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#define BUFFER_SIZE 1024
// 全局socket描述符
int sock;
// 互斥锁(保护socket操作)
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
/* 发送线程函数 */
void* send_thread(void* arg) {
while(1) {
char buffer[BUFFER_SIZE];
// 获取用户输入
if (fgets(buffer, BUFFER_SIZE, stdin) != NULL) {
// 加锁发送
pthread_mutex_lock(&lock);
send(sock, buffer, strlen(buffer), 0);
pthread_mutex_unlock(&lock);
}
}
return NULL;
}
/* 接收线程函数 */
void* recv_thread(void* arg) {
while(1) {
char buffer[BUFFER_SIZE] = {0};
int len;
// 加锁接收
pthread_mutex_lock(&lock);
len = recv(sock, buffer, BUFFER_SIZE, 0);
pthread_mutex_unlock(&lock);
if (len > 0) {
printf("收到消息: %s", buffer);
} else if (len == 0) {
printf("服务器断开连接\n");
break;
} else {
perror("接收错误");
break;
}
}
return NULL;
}
int main(int argc, char *argv[]) {
/* 参数校验 */
if (argc != 3) {
printf("用法: %s <IP地址> <端口号>\n", argv[0]);
exit(1);
}
/* 创建客户端socket */
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket创建失败");
exit(1);
}
/* 配置服务器地址 */
struct sockaddr_in serv_addr = {
.sin_family = AF_INET,
.sin_port = htons(atoi(argv[2])),
.sin_addr.s_addr = inet_addr(argv[1])
};
/* 为服务器准备ip和port(提前)
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr("192.168.110.223");
*/
/* 建立连接 */
if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("连接失败");
close(sock);
exit(1);
}
/* 发送客户端标识符 */
char client_id = '2';
send(sock, &client_id, 1, 0);
printf("已连接到服务器\n");
/* 创建发送和接收线程 */
pthread_t tid_send, tid_recv;
pthread_create(&tid_send, NULL, send_thread, NULL);
pthread_create(&tid_recv, NULL, recv_thread, NULL);
/* 等待线程结束(实际不会执行到这里) */
pthread_join(tid_send, NULL);
pthread_join(tid_recv, NULL);
close(sock);
return 0;
}
