实现2个客户端之间互相聊天
要求:
1、服务器使用 select 模型实现接受多个客户端连接,以及转发消息
2、客户端要求:使用 poll 模型解决 技能够 read 读取服务器发来的消息,又能够scanf读取键盘输入的信息
3、客户端服务器不允许开启额外线程和进程

服务器代码 (select模型)

#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 10
#define BUFFER_SIZE 1024int main(int argc, char *argv[]) {if (argc != 2) {printf("Usage: %s <port>\n", argv[0]);return 1;}int server_fd, new_socket, client_sockets[MAX_CLIENTS];struct sockaddr_in address;int opt = 1;int addrlen = sizeof(address);char buffer[BUFFER_SIZE] = {0};// 初始化客户端socket数组for (int i = 0; i < MAX_CLIENTS; i++) {client_sockets[i] = 0;}// 创建socketif ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("socket failed");exit(EXIT_FAILURE);}// 设置socket选项if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {perror("setsockopt");exit(EXIT_FAILURE);}address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(atoi(argv[1]));// 绑定socketif (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed");exit(EXIT_FAILURE);}// 监听if (listen(server_fd, 3) < 0) {perror("listen");exit(EXIT_FAILURE);}printf("Server started on port %d\n", atoi(argv[1]));fd_set readfds;int max_sd, activity;while (1) {FD_ZERO(&readfds);FD_SET(server_fd, &readfds);max_sd = 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_sd) {max_sd = client_sockets[i];}}// 使用select等待活动activity = select(max_sd + 1, &readfds, NULL, NULL, NULL);if ((activity < 0) && (errno != EINTR)) {perror("select error");}// 检查新连接if (FD_ISSET(server_fd, &readfds)) {if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {perror("accept");exit(EXIT_FAILURE);}printf("New connection, socket fd: %d, ip: %s, port: %d\n",new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));// 添加新socket到数组for (int i = 0; i < MAX_CLIENTS; i++) {if (client_sockets[i] == 0) {client_sockets[i] = new_socket;printf("Adding to list of sockets as %d\n", i);break;}}}// 检查客户端数据for (int i = 0; i < MAX_CLIENTS; i++) {int sd = client_sockets[i];if (FD_ISSET(sd, &readfds)) {int valread = read(sd, buffer, BUFFER_SIZE);if (valread == 0) {// 客户端断开连接getpeername(sd, (struct sockaddr*)&address, (socklen_t*)&addrlen);printf("Host disconnected, ip: %s, port: %d\n",inet_ntoa(address.sin_addr), ntohs(address.sin_port));close(sd);client_sockets[i] = 0;} else {// 转发消息给所有客户端buffer[valread] = '\0';printf("Forwarding message: %s\n", buffer);for (int j = 0; j < MAX_CLIENTS; j++) {if (client_sockets[j] > 0 && client_sockets[j] != sd) {send(client_sockets[j], buffer, strlen(buffer), 0);}}}}}}return 0;
}

客户端代码 (poll模型)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>#define BUFFER_SIZE 1024int main(int argc, char *argv[]) {if (argc != 3) {printf("Usage: %s <ip> <port>\n", argv[0]);return 1;}int sock = 0;struct sockaddr_in serv_addr;char buffer[BUFFER_SIZE] = {0};struct pollfd fds[2];// 创建socketif ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("socket creation failed");return -1;}serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(atoi(argv[2]));// 转换IP地址if (inet_pton(AF_INET, argv[1], &serv_addr.sin_addr) <= 0) {perror("invalid address");return -1;}// 连接服务器if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {perror("connection failed");return -1;}printf("Connected to server\n");// 设置poll结构fds[0].fd = STDIN_FILENO;    // 标准输入fds[0].events = POLLIN;fds[1].fd = sock;            // socketfds[1].events = POLLIN;while (1) {int ret = poll(fds, 2, -1); // 无限等待if (ret == -1) {perror("poll error");break;}// 检查键盘输入if (fds[0].revents & POLLIN) {memset(buffer, 0, BUFFER_SIZE);if (fgets(buffer, BUFFER_SIZE, stdin) == NULL) {break;}// 发送消息到服务器send(sock, buffer, strlen(buffer), 0);}// 检查服务器消息if (fds[1].revents & POLLIN) {memset(buffer, 0, BUFFER_SIZE);int len = recv(sock, buffer, BUFFER_SIZE, 0);if (len <= 0) {printf("Server disconnected\n");break;}printf("Received: %s", buffer);}}close(sock);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88991.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88991.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/88991.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iOS高级开发工程师面试——Objective-C 语言特性

iOS高级开发工程师面试——Objective-C 语言特性 一、多态二、继承三、代理(Delegate)1. 代理为什么用 weak 修饰呢?block和代理的区别?四、通知(NSNotificationCenter)五、KVC (Key-value Coding)六、属性七、`@property` [ˈprɒpəti]的本质是什么?ivar 、 setter …

MMpretrain 中的 LinearClsHead 结构与优化

LinearClsHead 结构与优化 一、LinearClsHead 核心结构 在 MMPretrain 中&#xff0c;LinearClsHead 是一个简洁高效的分类头&#xff0c;其核心结构如下&#xff1a; class LinearClsHead(BaseModule):def __init__(self,num_classes, # 类别数量in_channels, # 输入…

Spring 学习笔记

1.Spring AOP 怎么实现的AOP 即面向切面编程&#xff0c;是通过代理实现的&#xff0c;主要分为静态代理和动态代理&#xff0c;静态代理就是在程序运行前就已经指定并声明了代理类和增强逻辑&#xff0c;运行时就已经被编译为字节码文件了&#xff0c;而动态代理则是在运行过程…

【CVPR2024】计算机视觉|InceptionNeXt:速度与精度齐飞的CNN架构

论文地址&#xff1a;http://arxiv.org/pdf/2303.16900v3 代码地址&#xff1a;https://github.com/sail-sg/inceptionnext 关注UP CV缝合怪&#xff0c;分享最计算机视觉新即插即用模块&#xff0c;并提供配套的论文资料与代码。 https://space.bilibili.com/473764881 摘要…

7.15 窗口函数 | 二分 | 位运算 | 字符串dp

lc3316. 字符串dpdp多开一行一列后&#xff0c;注意原字符串下标映射dp[n][m] &#xff08; n 是source长度&#xff0c; m 是pattern长度&#xff09;两重循环填表for i 1-nfor j 0-m三种状态转移1.不选 dp i jdp i-1 j2.不选if tag, dp[i][j]3.if(s ip j) 选&#xff0c;dp i…

Spring原理揭秘--初识AOP

我们知道软件开发一直在追求高效&#xff0c;易维护&#xff0c;易扩展的特性方式。在面向过程编程到面向对象编程的历程中&#xff0c;程序的开发有了非常大的进步。但是oop的方式缺依然存在着一些缺点。oop的方式可以将业务进行很好的分解和封装使其模块化&#xff0c;但是却…

Provider模式:软件架构中的“供应商“设计哲学

文章目录Provider模式&#xff1a;软件架构中的“供应商“设计哲学什么是Provider模式&#xff1f;经典应用场景1. 配置管理Provider2. 数据访问Provider4. 消息队列ProviderProvider模式的优势1. 解耦合实际项目中的应用Provider模式的最佳实践1. 命名约定2. 接口设计原则3. 错…

LTspic下载,帮助及演示电路

1.下载 LTspice是一款强大高效的免费SPICE仿真器软件、原理图采集和波形观测器&#xff0c;为改善模拟电路的仿真提供增强功能和模型。其原理图捕获图形界面使您能够探测原理图并生成仿真结果&#xff0c;这些结果可以通过内置波形查看器进一步观察分析。 链接&#xff1a; …

位置编码/绝对位置编码/相对位置编码/Rope原理+公式详细推导及代码实现

文章目录1. 位置编码概述1.1 为什么需要位置编码&#xff1f;2. 绝对位置编码 (Absolute Position Encoding)2.1 原理2.2 数学公式2.3 代码实现2.4 代码与公式的对应关系2.5 特性与优势2.6 可学习的绝对位置编码3. 相对位置编码 (Relative Position Encoding)3.1 原理3.2 数学公…

网络安全初级第一次作业

一&#xff0c;docker搭建和挂载vpm 1.安装 Docker apt-get install docker.io docker-compose 2.创建文件 mkdir /etc/docker.service.d vim /etc/docker.service.d/http-proxy.conf 3.改写文件配置 [Service] Environment"HTTP_PROXYhttp://192.168.10.103:7890…

交换类排序的C语言实现

交换类排序包括冒泡排序和快速排序两种。冒泡排序基本介绍冒泡排序是通过重复比较相邻元素并交换位置实现排序。其核心思想是每一轮遍历将未排序序列中的最大&#xff08;或最小&#xff09;元素"浮动"到正确位置&#xff0c;类似气泡上升。基本过程是从序列起始位置…

嵌入式 Linux开发环境构建之Source Insight 的安装和使用

目录 一、Source Insight 的安装 二、Source Insight 使用 一、Source Insight 的安装 这个软件是代码编辑和查看软件&#xff0c;打开开发板光盘软件&#xff0c;然后右键选择以管理员身份运行这个安装包。在弹出来的安装向导里面点击 next &#xff0c;如下图所示。这里选择…

【字节跳动】数据挖掘面试题0016:解释AUC的定义,它解决了什么问题,优缺点是什么,并说出工业界如何计算AUC。

文章大纲 AUC(Area Under the Curve)详解一、定义:AUC是什么?二、解决了什么问题?三、优缺点分析四、工业界大规模计算AUC的方法1. 标准计算(小数据)2. 工业级大规模计算方案3.工业界最佳实践4.工业界方案选型建议总结:AUC的本质AUC(Area Under the Curve)详解 一、…

Python后端项目之:我为什么使用pdm+uv

在试用了一段时间的uv和pdm之后&#xff0c;上个月(2025.06)开始&#xff0c;逐步把用了几年的poetry替换成了pdmuv&#xff08;pipx install pdm uv && pdm config use_uv true) ## 为什么poetry -> pdm: 1. 通过ssh连接到服务器并使用poetry shell激活虚拟环境之…

鸿蒙Next开发,配置Navigation的Route

1. 通过router_map.json配置文件进行 创建页面配置router_map.json {"routerMap": [{"name": "StateExamplePage","pageSourceFile": "src/main/ets/pages/state/StateExamplePage.ets","buildFunction": "P…

在 GitHub 上创建私有仓库

一、在 GitHub 上创建私有仓库打开 GitHub官网 并登录。点击右上角的 “” → 选择 “New repository”。填写以下内容&#xff1a; Repository name&#xff1a;仓库名称&#xff0c;例如 my-private-repo。Description&#xff1a;可选&#xff0c;仓库描述。Visibility&…

量产技巧之RK3588 Android12默认移除导航栏状态栏​

本文介绍使用源码编译默认去掉导航栏/状态栏方法,以触觉智能EVB3588开发板演示&#xff0c;Android12系统&#xff0c;搭载了瑞芯微RK3588芯片&#xff0c;该开发板是核心板加底板设计&#xff0c;音视频接口、通信接口等各类接口一应俱全&#xff0c;可帮助企业提高产品开发效…

Conda 安装与配置详解及常见问题解决

《Conda 安装与配置详解及常见问题解决》 安装 Conda 有两种主流方式&#xff0c;分别是安装 Miniconda&#xff08;轻量级&#xff09;和 Anaconda&#xff08;包含常用数据科学包&#xff09;。下面为你详细介绍安装步骤和注意要点。 一、安装 Miniconda&#xff08;推荐&a…

Linux ——lastb定时备份清理

lastb 命令显示的是系统中 /var/log/btmp 文件中的SSH 登录失败记录。你可以像处理 wtmp 那样&#xff0c;对 btmp 文件进行备份与清理。✅ 一、备份 lastb 数据cp /var/log/btmp /var/log/btmp.backup.$(date %F)会保存为如 /var/log/btmp.backup.2025-07-14✅ 二、清空 lastb…

自定义类型 - 联合体与枚举(百度笔试题算法优化)

目录一、联合体1.1 联合体类型的声明1.2 联合体的特点1.3 相同成员的结构体和联合体对比1.4 联合体大小的计算1.5 联合练习二、枚举类型2.1 枚举类型的声明2.2 枚举类型的优点总结一、联合体 1.1 联合体类型的声明 像结构体一样&#xff0c;联合体也是由一个或者多个成员构成…