2024.8.21 作业

news2024/11/26 16:30:35

一个服务器和两个客户端聊天

代码:

/*******************************************/

文件名:server.c

/*******************************************/

#include <myhead.h>
#define SER_IP "192.168.2.7" // 服务器IP
#define SER_PORT 8888           // 服务器端口号
int main(int argc, const char *argv[])
{
    // 创建用于监听的套接字
    int sfd = -1;
    sfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sfd == -1)
    {
        perror("socket error");
        return -1;
    }
    printf("sfd = %d\n", sfd); // 3
    // 将端口号快速重用
    int reuse = 1;
    if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
    {
        perror("setsockopt error");
        return -1;
    }
    printf("端口号快速重用成功\n");
    // 绑定ip地址和端口号
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;                // 地址族
    sin.sin_port = htons(SER_PORT);          // 端口号
    sin.sin_addr.s_addr = inet_addr(SER_IP); // IP地址
    // 绑定
    if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
    {
        perror("bind error");
        return -1;
    }
    printf("bind success\n");
    // 启动监听,允许客户端连接
    if (listen(sfd, 128) == -1)
    {
        perror("listen error");
        return -1;
    }
    printf("listen success\n");
    struct sockaddr_in cin;          // 用于接收客户端地址信息结构体
    socklen_t socklen = sizeof(cin); // 用于接收客户端地址信息的大小
    int newfd = -1;                  // 新创建用于通信的套接字文件描述符
    char sbuf[128] = "";             // 从键盘上输入数据
    // 创建文件描述符容器
    fd_set readfds, tempfds;
    // 清空容器内容
    FD_ZERO(&readfds);
    // 将sfd和0号文件描述符放入容器中
    FD_SET(0, &readfds);
    FD_SET(sfd, &readfds);
    int maxfd = sfd;
    struct sockaddr_in cin_arr[1024];
    while (1)
    {
        tempfds = readfds; 
        int res = select(maxfd + 1, &tempfds, 0, 0, 0);
        if (res == -1)
        {
            perror("select error");
            return -1;
        }
        else if (res == 0)
        {
            printf("time out\n");
            return -1;
        }
        for (int i = 0; i <= maxfd; i++)
        {
            // 判断当前的文件描述符是否在tempfds中
            if (!FD_ISSET(i, &tempfds))
            {
                continue;
            }
            if (i == sfd) // 表示sfd触发了事件
            {
                newfd = accept(sfd, (struct sockaddr *)&cin, &socklen);
                if (newfd == -1)
                {
                    perror("accept error");
                    return -1;
                }
                printf("newfd = %d 您有新的客户已经上线\n", newfd);
                printf("客户端IP:%s, 端口号为:%d\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));
                // 将客户端文件描述符放入到集合中
                FD_SET(newfd, &readfds);
                cin_arr[newfd] = cin; // 将新的客户端地址信息放入容器
                // 更新maxfd
                if (newfd > maxfd)
                {
                    maxfd = newfd;
                }
            }
            else if (i == 0) // 表示有终端输入事件
            {
                // 输入数据
                fgets(sbuf, sizeof(sbuf), stdin);
                sbuf[strlen(sbuf) - 1] = 0;
                printf("触发了键盘输入事件:%s\n", sbuf);
                // 将消息发给每一个客户端
                for (int k = 4; k <= maxfd; k++)
                {
                    send(k, sbuf, strlen(sbuf), 0);
                }
            }
            else
            {
                // 通信套接字与客户端进行数据收发
                char rbuf[128] = "";
                // 清空容器
                bzero(rbuf, sizeof(rbuf));
                // 从套接字中读取数据
                int res = recv(i, rbuf, sizeof(rbuf), 0);
                if (res == 0)
                {
                    printf("客户端已经下线\n");
                    // 关闭套接字
                    close(i);
                    // 将当前文件描述符从容器中移除
                    FD_CLR(i, &readfds);
                    for (int j = maxfd; j >= 0; j--)
                    {
                        if (FD_ISSET(j, &readfds))
                        {
                            maxfd = j;
                            break;
                        }
                    }
                    continue;
                }
                printf("[%s:%d] :%s\n",inet_ntoa(cin_arr[i].sin_addr), ntohs(cin_arr[i].sin_port), rbuf);
                strcat(rbuf, "&&");
                send(i, rbuf, strlen(rbuf), 0);
            }
        }
    }
    close(sfd);
    return 0;
}

/*******************************************/

文件名:client.c

/*******************************************/

#include <myhead.h>
#define SER_IP "192.168.2.7" // 服务器IP
int main(int argc, const char *argv[])
{
    if(argc != 2)
    {
        printf("请输入正确的端口号\n");
        return -1;
    }
    // 创建服务器端套接字
    int cfd = -1;
    cfd = socket(AF_INET, SOCK_STREAM, 0);
    if (cfd == -1)
    {
        perror("socket error");
        return -1;
    }
    printf("sfd = %d\n", cfd); // 3
    // 将端口号快速重用
    int reuse = 1;
    if (setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
    {
        perror("setsockopt error");
        return -1;
    }
    printf("端口号快速重用成功\n");
    // 绑定ip地址和端口号
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;                // 地址族
    sin.sin_port = htons(8888);          // 端口号
    sin.sin_addr.s_addr = inet_addr(SER_IP); // IP地址
    struct sockaddr_in cin;          // 用于接收客户端地址信息结构体
    socklen_t socklen = sizeof(cin); // 用于接收客户端地址信息的大小
    int newfd = -1;                  // 新创建用于通信的套接字文件描述符
    char sbuf[128] = "";             // 从键盘上输入数据
    // 创建文件描述符容器
    fd_set readfds, tempfds;
    // 清空容器内容
    FD_ZERO(&readfds);
    // 将sfd和0号文件描述符放入容器中
    FD_SET(0, &readfds);
    FD_SET(cfd, &readfds);
    int maxfd = cfd;                  // 存放容器中最大的文件描述符的值
    struct sockaddr_in cin_arr[1024]; // 存放客户端对应的地址信息
    //连接到服务器
    if(connect(cfd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
    {
        perror("connect error");
        return -1;
    }
    printf("成功连接到服务器\n");
    while (1)
    {
        tempfds = readfds; 
        int res = select(maxfd + 1, &tempfds, 0, 0, 0); 
        if (res == -1)
        {
            perror("select error");
            return -1;
        }
        else if (res == 0)
        {
            printf("time out\n");
            return -1;
        }
        for (int i = 0; i <= maxfd; i++)
        {
            // 判断当前的文件描述符是否在tempfds中
            if (!FD_ISSET(i, &tempfds))
            {
                continue;
            }
            if (i == cfd) // 表示cfd触发了事件
            {
                //收到了服务器发来的消息
                char buf[128] = "";
                bzero(buf,sizeof(buf));
                recv(cfd, buf, sizeof(buf), 0);
                printf("%s\n",buf);
            }
 
            else if (i == 0) // 表示有终端输入事件
            {
                // 输入数据
                fgets(sbuf, sizeof(sbuf), stdin);
                sbuf[strlen(sbuf) - 1] = 0;
                printf("键盘输入:%s\n", sbuf);
                send(cfd, sbuf, sizeof(sbuf), 0);
            }
        }
    }
    close(cfd);
    return 0;
}

思维导图:

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

防火墙的原因导致:Arduino2.x下载安装后卡在LOGO

台式机之前使用arduino1.8没什么问题&#xff0c;升级到2.x后不能用了。由于arduino1.8还是可以能够使用的&#xff0c;关键台式机不是主力就凑合的。主力机笔记本升级arduino2.x能够使用&#xff0c;没有折腾了&#xff0c;这两天有空准备&#xff0c;折腾了一天。终于成果&am…

涂料耐久性氙灯老化试验箱

涂料氙灯老化试验箱是现代检测手段中常用的一种设备&#xff0c;它能够模拟自然光照、光照老化等环境条件&#xff0c;对涂料、染料、塑料、橡胶、纺织品、涂层等材料进行老化试验&#xff0c;以评估其耐久性和使用寿命。本文将详细介绍涂料氙灯老化试验箱的工作原理、使用注意…

MCU扩容新选择——SD NAND(单片机上搭配的SPI NOR FLASH容量告急!)

目录 注意&#xff1a; 前言&#xff1a;  问题与需求&#xff1a; SD NAND方案&#xff1a; NOR 与 NAND的区别&#xff1a; 总结&#xff1a; 插播广告&#xff1a; 128MB 详情页&#xff1a; PS: 传送门&#xff1a; 退路&#xff1a; 传送门; 注意&#xff1a;…

案例分享—优秀国外界面设计配色舒适的原因

国外的UI设计师通常接受过系统的色彩理论学习&#xff0c;他们深刻理解色彩对人的心理和感知的影响。在实际设计中&#xff0c;他们运用这些知识&#xff0c;通过巧妙的色彩搭配来创造出和谐、舒适的视觉效果&#xff0c;从而提升用户体验。 国外的UI设计在色彩搭配上往往更加注…

python中取list前2位

实用工具 list [1,2,3] print(list[:2])结果输出

时间序列分析2|ARIMA模型|SARIMA模型

ARMA模型的定阶 自相关和偏自相关系数法 通过观察样本的自相关系数(ACF)和偏自相关系数(PACF)&#xff0c;进行大体的判断 模型定阶的经验方法 截尾&#xff1a; 最初的d阶样本(偏)自相关系数明显在2倍标准差范围外95%的(偏)自相关系数都落在2倍标准差的范围以内非零自相…

RAM(随机存取存储器)都有哪些?(超详细)

目录 RAM的特点 RAM的类型 1. SRAM&#xff08;静态随机存取存储器&#xff09; 2. DRAM&#xff08;动态随机存取存储器&#xff09; 3. SDRAM&#xff08;同步动态随机存取存储器&#xff09; 4. DDR SDRAM&#xff08;双倍数据速率同步动态随机存取存储器&#xff09;…

GTC2024 回顾 | 优阅达携手 Power BI 赋能企业数据洞察,助力 AI 驱动的商业智能革新

随着 AI 加入&#xff0c;Power BI 更像是一个智能分析伙伴&#xff0c;帮助全球企业在数据驱动的商业世界中取得成功。 GTC 2024 全球流量大会&#xff08;深圳&#xff09;已圆满落幕。作为中国跨境出海领域最大的盛会之一&#xff0c;大会聚焦了行业内最前沿的创新技术和跨境…

Win10将用户文件夹迁移到其它磁盘

Windows的用户文件夹放在系统盘C盘,系统使用过程中,该文件夹会不断地增加一些文件,导致C盘空间不断减少。可将C盘用户文件夹迁移到其它磁盘,以解决此问题。 1、创建临时账户 首先创建一个临时账户。右击开始菜单,选择”计算机管理“,打开本地用户和组中的用户,在空白处…

图片太大不能上传怎么压缩变小?图片压缩变小的8个方法

在当今这个高度数字化的时代&#xff0c;图片作为信息传递的重要载体&#xff0c;其上传与分享变得日益频繁。然而&#xff0c;面对网络平台或应用对文件大小的严格限制&#xff0c;一张未经处理的图片往往显得过于庞大&#xff0c;难以顺利上传。这时&#xff0c;掌握图片压缩…

nginx的代理服务器

简介 Nginx是一款高性能的开源Web服务器和反向代理服务器&#xff0c;它以其稳定性、低资源消耗以及高并发处理能力而闻名。Nginx作为代理服务器&#xff0c;主要提供两种模式的服务&#xff1a;正向代理和反向代理。 实验准备 四台虚拟机&#xff1a;一台nginx代理服务器、两台…

博途PLC手自动控制功能块(FB和FC完整SCL源代码)

PLC面向对象编程系列之手动自动控制功能块 PLC面向对象编程系列之手动自动功能块(SMART PLC)_smart功能块怎么做-CSDN博客文章浏览阅读2.2k次。本文探讨了西门子S7-200 SMART PLC在手动和自动模式下控制设备的标准功能块实现,包括子程序接口设计、STL代码简化及SCL语言的应用…

火山引擎AI创新巡展:豆包比友商便宜98%,行业落地探索,2000人座无虚席,PPT值得拍照收藏

火山引擎AI创新巡展上海站今天举行&#xff0c;现场熙熙攘攘&#xff0c;初步估计&#xff0c;现场的2000个座位让参会者一座难求&#xff0c;还有很多站着的以及没能进到会场站着听的小伙伴。 外面展区也就那样&#xff0c;虽然有很多不错的创新&#xff0c;但整个内场还是挺…

基于Yolov5的安全帽检测系统设计与开发(论文+源码)_kaic​

摘 要 安全帽检测系统的设计意义在于提高工作场所的安全性和生产效率&#xff0c;通过安全帽检测系统可以实时监控工人是否佩戴安全帽&#xff0c;及时发现不佩戴安全帽的工人并进行提醒和警示&#xff0c;避免因为不佩戴安全帽导致意外事故的发生。因此&#xff0c;本文是一个…

SAP FI模块基础操作

1. 创建利润中心组, 成本控制范围 TCODE: KCH1/KCH2 按照树的层次结构分组层层配置 2. 创建利润中心 tcode&#xff1a;KE51/KE52 可参考创建&#xff0c;在控制范围下新增利润中心。配置利润中心对应的公司代码&#xff0c;部门&#xff0c;利润中心组等 利润中心主数据表…

分类预测 | Matlab实现BES-RF秃鹰搜索算法优化随机森林多特征分类预测

分类预测 | Matlab实现BES-RF秃鹰搜索算法优化随机森林多特征分类预测 目录 分类预测 | Matlab实现BES-RF秃鹰搜索算法优化随机森林多特征分类预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现BES-RF秃鹰搜索算法优化随机森林多特征分类预测&#xff0c;…

史上最全的软件工厂考试简答题教程

软件工程考试简答题 1. 有人认为软件开发时&#xff0c;一个错误发现得越晚&#xff0c;为改正它所付出的代价越大。提出你的观点并解释原因&#xff1f; &#xff08;1&#xff09;在软件开发的不同阶段进行修改付出的代价是很不相同的&#xff0c;在早期引入变动&#xff0c…

用 JavaScript 实现归并排序

目录 归并排序背后的逻辑 用 JavaScript 实现归并排序 归并排序的效率 总结 归并排序背后的逻辑 归并排序使用分而治之的概念对给定的元素列表进行排序。它将问题分解为较小的子问题&#xff0c;直到它们变得足够简单以至可以直接解决为止。 以下是归并排序的步骤&#xf…

C语言第16篇

1.定义如下变量: int n10; 则下列循环的输出结果是_______. while(n>7) { n--; printf("%d\n",n);} A) 10 B) 9 C) 10 D) 9 9 8 9 8 8 7 8 7 7 6 提…

Java 入门指南:注解(Annotation)

注解的基本概念 Java注解&#xff08;Annotation&#xff09;是一种附加在代码中的元数据&#xff0c;用于对程序代码进行说明和补充。同 class 类 和 interface 接口 一样&#xff0c;也属于一种类型。它是在 Java SE 5 中引入的一项新特性&#xff0c;常用于配置、编译和运行…