3.5作业

课程代码复习:

使用select完成TCP并发服务器:

#include<myhead.h>
#define SER_IP "192.168.244.140"  //服务器IP
#define SER_PORT 8888            //服务器端口号

int main(int argc, const char *argv[])
{
    //1、创建用于监听的套接字
    int sfd = -1;
    sfd=socket(AF_INET, SOCK_STREAM, 0);
    //参数1:表示使用的是ipv4的通信
    //参数2:表示使用tcp通信类型
    //参数3:表示前面已经特定了通信协议
    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");


    //2、绑定ip地址和端口号
    //2.1填充地址信息结构体
    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地址
    //2.2绑定
    if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin))==-1)
    {
        perror("bind error");
        return -1;
    }
    printf("bind success\n");

    
    //3、启动监听,允许客户端连接
    if(listen(sfd, 128) == -1)
    {
        perror("listen error");
        return -1;
    }

    printf("listen success\n");
    
    //4、当有客户端发来连接请求后创建新的用于通信的套接字
    //如果不想接收客户端地址信息结构体,则无需传入参数2和参数3
    //如果想要获取客户端地址信息结构体,则需要传入相关参数
    
    struct sockaddr_in cin;       //用于接收客户端地址信息结构体
    socklen_t socklen = sizeof(cin);     //用于接收客户端地址信息的大小
    int newfd = -1;            //新创建用于通信的套接字文件描述符
    char sbuf[128] = "";        //从键盘上输入数据

    //1、创建文件描述符容器
    fd_set readfds, tempfds;
    //2、清空容器内容
    FD_ZERO(&readfds);
    //3、将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, NULL, NULL, NULL);  //阻塞等待集合中事件产生
        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;
            }

            //如果程序执行到此,说明检测的集合中的i文件描述符产生了事件

            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
            {
                //5、通信套接字与客户端进行数据收发
                char rbuf[128] = "";

                //清空容器
                bzero(rbuf, sizeof(rbuf));

                //从套接字中读取数据
                int res = recv(i, rbuf, sizeof(rbuf), 0);
                if(res == 0)
                {
                    printf("客户端已经下线\n");
                    //6、关闭套接字
                    close(i);

                    //将当前文件描述符从容器中移除
                    FD_CLR(i, &readfds);
                    //更新maxfd
                    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;
}

使用poll完成tcp客户端

#include<myhead.h>
#define SER_IP "192.168.244.140"      //服务器ip
#define SER_PORT 8888               //服务器端口号

#define CLI_IP "192.168.244.140"      //客户端IP
#define CLI_PORT 9999                //客户端端口号

int main(int argc, const char *argv[])
{
    //1、创建用于通信的套接字文件描述符
    int cfd = socket(AF_INET, SOCK_STREAM, 0);
    if(cfd == -1)
    {
        perror("socket error");
        return -1;
    }
    printf("cfd = %d\n", cfd);          //3

    //2、绑定(非必须)
    //2.1 填充地址信息结构体
    struct sockaddr_in cin;
    cin.sin_family = AF_INET;
    cin.sin_port = htons(CLI_PORT);
    cin.sin_addr.s_addr = inet_addr(CLI_IP);
    //2.2 绑定
    if(bind(cfd, (struct sockaddr*)&cin, sizeof(cin)) == -1)
    {
        perror("bind error");
        return -1;
    }

    printf("bind success\n");
    
    //3、连接服务器
    //3.1填充要连接的服务器地址信息结构体
    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地址

    //3.2 连接服务器
    if(connect(cfd, (struct sockaddr*)&sin, sizeof(sin))==-1)
    {
        perror("connect error");
        return -1;
    }
    printf("connect success\n");

    //使用poll完成客户端的读写操作并发执行
    //1、定义一个pollfd数组
    struct pollfd pfd[2];
    pfd[0].fd = 0;         //检测0号文件描述符
    pfd[0].events = POLLIN;   //检测0号文件描述符的读操作

    pfd[1].fd = cfd;          //检测cfd文件描述符
    pfd[1].events = POLLIN;  //检测cfd中的读操作
    

    //4、数据收发
    char wbuf[128] = "";
    while(1)
    {
        int res = poll(pfd, 2, -1);   //阻塞检测集合中是否有事件产生
        if(res == -1)
        {
            perror("poll error");
            return -1;
        }else if(poll == 0)
        {
            printf("time out\n");
            return -1;
        }

        //程序执行至此,表示有事件产生
        if(pfd[0].revents == POLLIN)              //表示0号文件描述符事件产生
        {

            //清空数据
            bzero(wbuf, sizeof(wbuf));

            printf("请输入>>>");
            fgets(wbuf, sizeof(wbuf), stdin);   //从终端输入
            wbuf[strlen(wbuf)-1] = 0;

            //将数据发送给服务器
            send(cfd, wbuf, strlen(wbuf), 0);
            printf("发送成功\n");

            //判断发送的数据
            if(strcmp(wbuf, "quit") == 0)
            {
                break;
            }
        }

        if(pfd[1].revents == POLLIN)         //表示cfd文件描述符事件产生
        {
            //接收服务器发来的消息
            //清空数据
            bzero(wbuf, sizeof(wbuf));
            recv(cfd, wbuf, sizeof(wbuf), 0); 

            printf("收到消息为:%s\n", wbuf);
        }

    }


    //5、关闭套接字
    close(cfd);

    return 0;
}

课程总结:

提问总结:

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

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

相关文章

6. 虚拟机及Linux安装

虚拟机及Linux安装 进行嵌入式项目开发&#xff0c;第一步就是要建立嵌入式开发环境&#xff0c;主要包括安装 Bootloader 工具、不同平台的交叉编译器&#xff08;如ARM 平台的arm-linux-gcc&#xff09;、内核源码树&#xff08;在需要编译和配置内核时&#xff09;、在调试…

docker学习进阶

一、dockerfile解析 官方文档&#xff1a; Dockerfile reference | Docker Docs 1.1、dockfile是什么&#xff1f; dockerfile是用来构建docker镜像的文本文件&#xff0c;由一条条构建镜像所需的指令和参数构成的脚本。 之前我们介绍过通过具体容器反射构建镜像(docker comm…

第11周,第三期技术动态

大家好&#xff0c;才是真的好。 真没想到&#xff0c;本周是今年第十一周&#xff0c;2024年还有不到三百天就结束了。 今天周五&#xff0c;我们继续介绍与Domino相关产品新闻&#xff0c;以及互联网或其他IT行业动态等。 一、在Windows 10和Windows 11上运行Domino和Trav…

错误和异常之标准异常创建异常

标准异常 表 10.2 列出了所有的 Python 当前的标准异常集,所有的异常都是内建的. 所以它们在脚本启动 前或在互交命令行提示符出现时已经是可用的了. 表10.2 Python内建异常 异常名称描述所有异常的基类 python 解释器请求退出 用户中断执行(通常是输入^C) 常规错误的基类

大模型时代下的自动驾驶研发测试工具链-SimCycle

前言&#xff1a; 最近OpenAI公司的新产品Sora的发布&#xff0c;正式掀起了AI在视频创作相关行业的革新浪潮&#xff0c;AI不再仅限于文本、语音和图像&#xff0c;而直接可以完成视频的生成&#xff0c;这是AI发展历程中的又一座重要的里程碑。AI正在不断席卷着过去与我们息…

仿牛客项目Day02:http、调试、日志、git

http状态码 后端调试 f8&#xff1a;逐行执行 f7&#xff1a;进入语句内部 f9&#xff1a;执行到下一个断点 前端调试 f10&#xff1a;逐行调试 f11&#xff1a;进入语句内部 f8&#xff1a;执行到下一个断点 日志 按照级别开启日志 日志的测试类 比如把application里…

基于交叉表生成风控规则(Python)

大家好&#xff0c;我是东哥。 规则是风控策略中最常用的工具之一&#xff0c;生成、筛选、监控、调优&#xff0c;几乎每天都在打交道&#xff0c;本篇来介绍如何基于交叉表来生成风控规则&#xff0c;并且如何基于评估指标进行筛选。 出品人&#xff1a;东哥起飞 专栏&#…

【字符串】【分类讨论】【KMP】1163. 按字典序排在最后的子串

作者推荐 视频算法专题 本文涉及知识点 字符串 字典序 分类讨论 本题无法使用KMP&#xff0c;因为t1不段变化。 LeetCode1163. 按字典序排在最后的子串 给你一个字符串 s &#xff0c;找出它的所有子串并按字典序排列&#xff0c;返回排在最后的那个子串。 示例 1&#xf…

图论入门题题解

✨欢迎来到脑子不好的小菜鸟的文章✨ &#x1f388;创作不易&#xff0c;麻烦点点赞哦&#x1f388; 所属专栏&#xff1a;刷题_脑子不好的小菜鸟的博客-CSDN博客 我的主页&#xff1a;脑子不好的小菜鸟 文章特点&#xff1a;关键点和步骤讲解放在 代码相应位置 拓扑排序 / 家谱…

基于Docker搭建Maven私服仓库(Linux)详细教程

文章目录 1. 下载镜像并启动容器2. 配置Nexus3. 配置本地Maven仓库 1. 下载镜像并启动容器 下载Nexus3镜像 docker pull sonatype/nexus3查看Nexus3镜像是否下载成功 docker images创建Nexus3的挂载文件夹 mkdir /usr/local/nexus-data && chown -R 200 /usr/local…

cadence 之 Allegro PCB封装 3D模型

Allegro PCB封装怎样赋3D模型 1、方式一 —— 设置器件高度 2、方式二 —— 指定STEP模型 2.1、Step 3D模型库 2.2、软件环境的设置和 STEP 模型库路径设置 D:\Cadence\Cadence_SPB_17.4-2019\share\local\pcb\step 2.3、指定STEP模型 即可打开 STEP 模型指定的对话框&…

【HarmonyOS】ArkTS-对象方法

目录 对象方法实例 对象方法 方法作用&#xff1a;描述对象的具体行为 约定方法类型 interface 接口名称 { 方法名: (参数:类型) > 返回值类型 }interface Person{dance: () > voidsing: (song: string) > void}添加方法&#xff08;箭头函数&#xff09; let ym: P…

服务器配置禁止IP直接访问,只允许域名访问

联网信息系统需设置只允许通过域名访问&#xff0c;禁止使用IP地址直接访问&#xff0c;建议同时采用云防护技术隐藏系统真实IP地址且只允许云防护节点IP访问服务器&#xff0c;提升网络安全防护能力。 一、Nginx 修改配置文件nginx.conf&#xff0c;在server段里插入正则表达式…

【C++ 学习】构造函数详解!!!

1. 类的6个默认成员函数的引入 ① 如果一个类中什么成员都没有&#xff0c;简称为空类。 ② 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 ③ 默认成员函数&#xff1a;用户没有显式实现&…

LoadBalancer 客户端的负载均衡器+openFeign 请求转发

LoadBalancer Spring Cloud LoadBalancer是Spring Cloud中负责客户端负载均衡的模块&#xff0c;其主要原理是从nacos中获取服务列表通过选择合适的服务实例来实现负载均衡。 源码跟踪 可以看到这里的intercept()方法&#xff0c;拦截了用户的HttpRequest请求&#xff0c;然…

在IDEA使用HBase Java API连接

一、下载安装Maven并加载到IDEA中 官网地址:Maven – Download Apache Maven 将对应版本的压缩包下载到本地,并新建一个文件夹Localwarehouse&#xff0c;用来保存下载的依赖文件 配置maven的系统环境配置&#xff0c;将maven安装的bin目录地址写入path环境变量&#xff1a; …

机器学习--循环神经网络(RNN)4

一、RNN的学习方式 如果要做学习&#xff0c;需要定义一个损失函数&#xff08;loss function&#xff09;来评估模型的好坏&#xff0c;选一个参数要让损失最小。 以槽填充为例&#xff0c;如上图所示&#xff0c;给定一些句子&#xff0c;给定一些标签&#xff0c;告诉机器…

【软件工程导论】——软工学绪论及传统软件工程(学习笔记)

&#x1f4d6; 前言&#xff1a;随着软件产业的发展&#xff0c;计算机应用逐步渗透到社会生活的各个角落&#xff0c;使各行各业都发生了很大的变化。这同时也促使人们对软件的品种、数量、功能和质量等提出了越来越高的要求。然而&#xff0c;软件的规模越大、越复杂&#xf…

测试环境搭建整套大数据系统(九:docker学习)

一&#xff1a;为什么学习dockder&#xff1f; 对于组件的搭建和部署&#xff0c;可以简化。 二&#xff1a;什么是docker&#xff1f; docker是一个平台。 三&#xff1a;怎么使用docker&#xff1f; 1. 安装&#xff0c;切换仓库。 安装 curl -fsSL https://test.docke…

[java基础揉碎]继承

为什么需要继承: > 继承就可以解决代码复用的问题 继承的基本介绍: 继承的使用细节: 1.子类继承了所有的属性和方法&#xff0c;但是私有属性和方法不能在子类直接访问&#xff0c;要通过公共的方法去访问 解决, 提供公共的方法返回: 2.子类必须调用父类的构造器,完成父…