2024.8.21 作业

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

代码:

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

文件名: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.mfbz.cn/a/871591.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C#开发基础之100个常用的C#正则表达式

前言 正则表达式是处理字符串的强大工具&#xff0c;特别是在文本搜索、替换和验证中。本文将100个常用的C#正则表达式进行分类&#xff0c;以帮助我们更快速地找到适合的正则表达式解决方案。 1. 基础匹配 这些正则表达式用于匹配一些基本的字符或字符串模式。 匹配任意字…

Linux信号机制探析--信号的产生

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 目录 &#x1f4da;信号什么是信号&#xff1f;为什么要有信号&#xff1f;查看Linux系统中信号 &#x1f388;信号产生&#x1f4d5;kill…

【计算机网络】网络版本计算器

此前我们关于TCP协议一直写的都是直接recv或者read&#xff0c;有了字节流的概念后&#xff0c;我们知道这样直接读可能会出错&#xff0c;所以我们如何进行分割完整报文&#xff1f;这就需要报头来解决了&#xff01; 但当前我们先不谈这个话题&#xff0c;先从头开始。 将会…

Kubectl命令、初识pod、namespace

文章目录 一、Kubectl简介基础命令1.基本信息命令2.创建和更新资源命令3.删除资源命令4. 查看日志和调试命令5. 端口转发和复制文件命令6. 部署管理命令7. 伸缩命令8. 配置和上下文管理命令9.常用命令 二、Pod简介核心概念pod常见状态调度和初始化阶段容器创建和运行阶段异常状…

Zookeeper服务注册及心跳机制详解

ZooKeeper提供了一种类似于文件目录的结构来保存key值&#xff0c;其提供了四种key类型&#xff0c;分别是持久节点&#xff0c;临时节点&#xff0c;持久有序节点&#xff0c;临时有序节点。其中临时节点的特性是当创建此节点的会话断开时&#xff0c;节点也会被删除。这一特性…

Apache Commons-IO 库

Apache Commons-IO是Apache开源基金组织提供的一组有关IO&#xff08;Input/Output&#xff09;操作的小框架。这个库的主要目的是为了提高IO流的开发效率&#xff0c;减少在进行文件读写、目录遍历等操作时编写的样板代码量。通过使用Commons-IO库&#xff0c;开发者可以更加简…

WT32-ETH01开发板模块,启明云端物联网方案,乐鑫ESP32多样化开发应用

在物联网(IoT)的浪潮中&#xff0c;无线Wi-Fi模块作为连接传统硬件与现代智能网络的桥梁&#xff0c;正逐渐成为智能家居和设备通信不可或缺的一部分。Wi-Fi模块也被称为串口Wi-Fi模块&#xff0c;是一种嵌入式模块&#xff0c;它能够将串口或TTL电平信号转换为符合Wi-Fi无线网…

关于AR在医疗领域创新应用

AR技术在医疗领域创新应用&#xff0c;旨在展示AR技术如何为医疗行业带来革命性的变化&#xff0c;我们可以从以下几个方面入手&#xff1a; 一、引言 随着科技的飞速发展&#xff0c;增强现实&#xff08;AR&#xff09;技术正逐步渗透到医疗领域的各个环节&#xff0c;为患…

蓝桥杯2021第十二届蓝桥杯青少年组省赛试题真题

带我去看题解&#xff01;&#xff01;&#xff01; 带我去看题单&#xff01;&#xff01;&#xff01; 目录 第一题&#xff1a;[2021第十二届蓝桥杯青少年组省赛] 字符串 题目背景 题目描述 输入格式 输出格式 输入输出样例 第二题&#xff1a;[2021第十二届蓝桥杯…

【Docker】安装Docker环境遇到的坑(VirtualBox)

利用vagrant工具在VirtualBox安装CentOS7环境后&#xff0c;安装Docker环境遇到的坑 前期准备工作 1、卸载原有环境 sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engi…

Spire.PDF for .NET【文档操作】演示:创建 PDF 组合

PDF 作品集是一组文件&#xff0c;其中可以包含文本文档、电子表格、电子邮件、图像、PowerPoint 演示文稿和绘图。尽管 PDF 作品集将不同类型的文件组合成一个单元&#xff0c;但其中的每个文件都保留了其原始格式、分辨率和大小。在本文中&#xff0c;您将学习如何使用Spire.…

C#实现数据采集系统-多设备采集

系统功能升级-多设备采集 数据采集系统在网络环境下&#xff0c;性能足够&#xff0c;可以实现1对多采集&#xff0c;需要支持多个设备进行同时采集功能&#xff0c;现在就开发多设备采集功能 修改多设备配置 设备配置 将DeviceLink 改成List集合的DeviceLinks删掉Points&a…

datawind可视化查询-其他函数

飞书文档学习链接:https://www.volcengine.com/docs/4726/47275 1. 用户名函数 用户名函数并非 ClickHouse 官方函数,而是与项目用户信息相结合,用于返回当前使用用户的指定信息的函数。 USERNAME()可返回当前用户的用户名,如下所示。该函数也可与其他函数组合使用 2. J…

Android 应用集成百度地图定位SDK

在当今的移动互联网时代&#xff0c;位置服务已经成为了众多应用不可或缺的功能之一。无论是社交应用中的位置分享&#xff0c;还是服务类应用中的位置导航&#xff0c;都离不开精准的定位技术。为了满足这一需求&#xff0c;越来越多的开发者选择集成第三方的定位SDK。其中&am…

【ARM Hypervisor And SMMU 系列 5 -- SMMU 和 IOMMU技术】

文章目录 SMMU 和 IOMMU技术ARM 的 SMMUTranslation process overviewTBU 和 TCU 的关系TBUTCUTLBSMMU 和 IOMMU技术 文章 讲到了为支持I/O透传机制中的DMA设备传输而引入的IOMMU/SMMU技术,同时留了一个问题:IOMMU/SMMU是否可以同时支持GVA->GPA和GPA->HPA的转换? 答案…

三种相机模型总结(针孔、鱼眼、全景)

相机标定 文章目录 相机标定前言 前言 我们最常见的投影模型Perspective Projection Model描述的就是针孔相机的成像原理。从上面的图根据相似三角形可以得出 参考链接 https://zhuanlan.zhihu.com/p/540969207 相机标定之张正友标定法数学原理详解&#xff08;含python源码&a…

SpingBoot集成kafka发送读取消息

SpingBoot集成kafka开发 kafka的几个常见概念 1、springboot和kafka对应版本&#xff08;重要&#xff09;2、创建springboot项目&#xff0c;引入kafka依赖2.1、生产者EventProducer2.2、消费者EventConsumer2.3、启动生产者的方法SpringBoot01KafkaBaseApplication2.4、appli…

蓝队技能-应急响应篇挖矿病毒系统样本家族威胁情报异常定性排查分析处置封锁

知识点 1、应急响应-挖矿病毒-定性&排查 2、应急响应-挖矿病毒-应急&处置演示案例-蓝队技能-挖矿病毒-样本&定性&排查&应急&处置 挖矿病毒 随着虚拟货币的疯狂炒作&#xff0c;挖矿病毒已经成为不法分子利用最为频繁的攻击方式之一。 可以利用个人电…

[论文笔记]Improving Retrieval Augmented Language Model with Self-Reasoning

引言 今天带来一篇百度提出的关于提升RAG准确率的论文笔记&#xff0c;Improving Retrieval Augmented Language Model with Self-Reasoning。 为了简单&#xff0c;下文中以翻译的口吻记录&#xff0c;比如替换"作者"为"我们"。 检索增强语言模型(Retrie…

你应该停止使用的 7 个已弃用的 Python 库

欢迎来到雲闪世界。升级您的 Python 工具包&#xff1a;发现 7 个应停止使用的过时库以及替代它们的功能。最近&#xff0c;我回顾了 Python 的新特性&#xff0c;发现每个版本都引入了创新&#xff0c;使我们的日常开发工作变得更加轻松。 这让我意识到科技是一门永无止境的艺…