实现2个客户端之间互相聊天
要求:服务器使用 select 模型实现接受多个客户端连接,以及转发消息;
客户端要求:使用 poll 模型解决 技能够 read 读取服务器发来的消息,又能够scanf读取键盘输入的信息;客户端服务器不允许开启额外线程和进程。
服务器
#include <head.h>
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};// 创建监听套接字
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}// 设置套接字选项
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
&opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8888);// 绑定地址
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 监听
if (listen(server_fd, 100) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(server_fd, &read_fds);
int max_fd = server_fd;while (1) {
fd_set temp_fds = read_fds;
int activity = select(max_fd + 1, &temp_fds, NULL, NULL, NULL);if (activity < 0) {
perror("select error");
break;
} else if (activity > 0) {
if (FD_ISSET(server_fd, &temp_fds)) {
// 新连接请求
if ((new_socket = accept(server_fd,
(struct sockaddr *)&address,
(socklen_t *)&addrlen)) < 0) {
perror("accept");
continue;
}
FD_SET(new_socket, &read_fds);
if (new_socket > max_fd) {
max_fd = new_socket;
}
} else {
// 已有客户端发送消息
for (int i = 0; i <= max_fd; i++) {
if (FD_ISSET(i, &temp_fds)) {
int valread = read(i, buffer, 1024);
if (valread == 0) {
// 客户端断开连接
close(i);
FD_CLR(i, &read_fds);
} else {
buffer[valread] = '\0';
// 转发消息给其他客户端
for (int j = 0; j <= max_fd; j++) {
if (j != server_fd && j != i && FD_ISSET(j, &read_fds)) {
write(j, buffer, strlen(buffer));
}
}
}
}
}
}
}
}
return 0;
}
客户端
#include <head.h>
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
char buffer[1024] = {0};
struct pollfd fds[2];// 创建套接字
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket creation error");
return -1;
}serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8888);// 将IP地址转换为网络字节序
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
perror("invalid address/ Address not supported");
return -1;
}// 连接到服务器
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("connection failed");
return -1;
}fds[0].fd = 0; // 标准输入
fds[0].events = POLLIN;
fds[1].fd = sock;
fds[1].events = POLLIN;while (1) {
int poll_result = poll(fds, 2, -1);
if (poll_result < 0) {
perror("poll error");
break;
} else if (poll_result > 0) {
if (fds[0].revents & POLLIN) {
// 键盘输入
fgets(buffer, 1024, stdin);
buffer[strcspn(buffer, "\n")] = '\0';
send(sock, buffer, strlen(buffer), 0);
}
if (fds[1].revents & POLLIN) {
// 服务器消息
int valread = read(sock, buffer, 1024);
if (valread == 0) {
// 服务器断开连接
printf("服务器断开连接\n");
break;
} else {
buffer[valread] = '\0';
printf("已收到: %s\n", buffer);
}
}
}
}
close(sock);
return 0;
}
188

被折叠的 条评论
为什么被折叠?



