day7-网络编程

1>基于UDP的网络聊天室

Ser.c

#include <myhead.h>
#define SER_IP "10.211.55.9" // 服务器IP
#define SER_PORT 9999

struct user
{
    char usrName[20];
    struct sockaddr_in cin;
};
int main(int argc, char const *argv[])
{
    // 1.创建用于监听的套接字
    int sfd = -1;
    sfd = socket(AF_INET, SOCK_STREAM, 0);
    // 参数1:表示使用的是ipv4的通信
    // 参数2:表示使用tcp通信类型
    // 参数3:表示前面已经特定了通信协议
    if (sfd == -1)
        PRINT_ERR("");
    printf("sfd = %d\n", sfd);

    int reuse = 1;
    if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
        PRINT_ERR("");

    // 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");

    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 user User[1024];

    while (1)
    {
        tempfds = readfds; //  将要检测的容器复制保存一份

        int res = select(maxfd + 1, &tempfds, NULL, NULL, NULL);
        if (res == -1)
            PRINT_ERR("select error");
        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)
            {
                newfd = accept(i, (struct sockaddr *)&cin, &socklen);
                if (newfd == -1)
                    PRINT_ERR("");

                recv(newfd, User[newfd].usrName, sizeof(User[newfd].usrName), 0);
                printf("%s [%s:%d]登陆成功\n", User[newfd].usrName, inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));

                // 将客户端文件描述符放入集合中
                FD_SET(newfd, &readfds);

                // 更新maxfd
                if (newfd > maxfd)
                {
                    maxfd = newfd;
                }

                // 打包信息
                bzero(sbuf, sizeof(sbuf));
                sprintf(sbuf,"-----%s登陆成功-----",User[newfd].usrName);
            //    strcat(sbuf, "-----");
            //    strcat(sbuf, User[newfd].usrName);
            //    strcat(sbuf, "登陆成功-----");

                // 将消息发给每一个客户端
                for (int k = 4; k <= maxfd; k++)
                {
                    if (k == i)
                        continue;
                    send(k, sbuf, strlen(sbuf), 0);
                }
            }
            else if (i == 0) // 表示有终端输入事件
            {
                // 将消息发送给每一个客户端
                bzero(sbuf, sizeof(sbuf));
                fgets(sbuf, sizeof(sbuf), stdin);
                sbuf[strlen(sbuf) - 1] = 0;

                char sbuf1[128] = "Sys:";
                strcat(sbuf1, sbuf);

                // 将消息发给每一个客户端
                for (int k = 4; k <= maxfd; k++)
                {
                    send(k, sbuf1, strlen(sbuf1), 0);
                }
            }
            else
            {
                // 5、通信套接字与客户端进行数据收发
                char rbuf[128] = ""; // 数据读取

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

                // 从套接字中读取数据
                int res = recv(i, rbuf, sizeof(rbuf), 0);
                if (res == 0)
                {

                //    strcat(rbuf, "-----");
                //    strcat(rbuf, User[i].usrName);
                //    strcat(rbuf, " 已下线-----");
                    sprintf(rbuf,"-----%s已下线-----",User[i].usrName);
                    // 将消息发给每一个客户端
                    for (int k = 4; k <= maxfd; k++)
                    {
                        if (k == i)
                            continue;
                        send(k, rbuf, strlen(rbuf), 0);
                    }

                    bzero(User[i].usrName, sizeof(User[i].usrName));

                    // 6、关闭套接字
                    close(i);

                    // 将当前文件描述符从容器中移除
                    FD_CLR(i, &readfds);

                    // 更新maxfd
                    for (int j = maxfd; j >= 0; j--)
                    {
                        if (FD_ISSET(j, &readfds))
                        {
                            maxfd = j;
                            break;
                        }
                    }
                }
                else if (strcmp(rbuf, "quit") != 0)
                {
                    printf("%s [%s:%d]chart成功\n", User[i].usrName, inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));

                    char wbuf[128] = "";
                    strcat(wbuf, User[i].usrName);
                    strcat(wbuf, ":");
                    strcat(wbuf, rbuf);
                    // 将消息发给每一个客户端
                    for (int k = 4; k <= maxfd; k++)
                    {
                        if (k == i)
                            continue;
                        send(k, wbuf, strlen(wbuf), 0);
                    }
                }
                bzero(rbuf, sizeof(rbuf));
            }
        }
    }

    close(sfd);
    return 0;
}

Cli.c

#include <myhead.h>
#define SER_IP "10.211.55.9" // 服务器IP
#define SER_PORT 9999

struct msgTyp
{
    char usrName[20];
    char msgText[1024];
};

int main(int argc, const char *argv[])
{
    struct msgTyp User = {0, 0};
    printf("请输入姓名>>>");
    scanf("%s", User.usrName);

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

    // 2、绑定(非必须)

    // 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");

    //向服务器发送上线信息
    send(cfd, User.usrName, strlen(User.usrName), 0);

    // 使用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、数据收发
    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(&User.msgText, sizeof(User.msgText));

            fgets(User.msgText, sizeof(User.msgText), stdin); // 从终端输入
            User.msgText[strlen(User.msgText) - 1] = 0;

            // 将数据发送给服务器
            send(cfd, User.msgText, strlen(User.msgText), 0);
            
            // 判断发送的数据
            if (strcmp(User.msgText, "quit") == 0)
            {
                break;
            }
        }

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

            printf("%s\n", User.msgText);
        }
    }

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

    return 0;
}

结果:

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

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

相关文章

coqui-ai/TTS 案例model文件

GitHub - coqui-ai/TTS: &#x1f438;&#x1f4ac; - a deep learning toolkit for Text-to-Speech, battle-tested in research and production Coqui AI的TTS是一款开源深度学习文本转语音工具&#xff0c;以高质量、多语言合成著称。它提供超过1100种语言的预训练模型库&…

Elemenu中el-table中使用el-popover选中关闭无效解决办法

主要是技术太菜,没找到原因,一点点才找到这个办法解决 因为在el-table-column里,因为是多行,使用trigger"manual" 时,用v-model"visible"来控制时,控件找不到这个值,才换成trigger"click" 先找到弹出关闭事件,再找元素的属性 右键>审核元素…

哪款洗地机值得买?希亦、追觅、米博、美的谁才是行业标杆?

在家庭清洁中&#xff0c;最让我们苦恼的便是厨房垃圾了&#xff0c;油渍跟食物残渣&#xff0c;用扫把扫了后&#xff0c;要反反复复的湿拖五六次&#xff0c;期间不停的手洗拖把&#xff0c;这套流程下来&#xff0c;往往容易腰酸背痛&#xff0c;手指皱巴巴的&#xff0c;这…

Java项目:40 springboot月度员工绩效考核管理系统009

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本系统的功能分为管理员和员工两个角色 管理员的功能有&#xff1a; &#xff08;1&#xff09;个人中心管理功能&#xff0c;添加管理员账号…

【BUG修复日志】Anaconda + VSCode 编码错误

【BUG修复日志】Anaconda VSCode 编码错误 平台: Windows11家庭版 (v22621.3155) 软件: Visual Studio Code (v1.87.0) 插件: Python (v2024.2.1) 版本: Conda (v24.1.2)问题描述 VSCode 在安装 Python 插件的情况下自动提示配置 Conda 环境&#xff0c;但是在自动配置完成后…

SpringMVC实用技术

1.校验框架 1.表单校验框架入门 表单校验的重要性 数据可以随意输入&#xff0c;导致错误的结果。表单校验保障了数据有效性、安全性 表单校验分类 校验位置&#xff1a; 客户端校验 服务端校验 校验内容与对应方式&#xff1a; 格式校验 客户端&#xff1a;使用Js技术…

【linuxC语言】系统调用IO文件操作

文章目录 前言一、文件描述符介绍二、系统调用IO API介绍2.1 open函数2.2 close函数2.3 read函数2.4 write函数2.5 lseek函数 三、示例代码总结 前言 在Linux系统中&#xff0c;C语言通过系统调用实现对文件的输入输出&#xff08;I/O&#xff09;操作。系统调用提供了访问操作…

LLM - 使用 Langchain 实现本地 Naive RAG

目录 一.引言 二.构建本地 Langchain 库 1.Doc 知识文档 2.Split 文档切分 3.Encode 内容编码 4.Similar 本地库构建 三.缓存本地 Langchain 库 四.读取本地 Langchain 库 1.Load 读取缓存 2.Similar 预测 3.Add 添加文档 五.总结 一.引言 上一篇博客介绍了当下 R…

M2TS转MP4怎么转?超快的方法~

M2TS格式的优点主要体现在对高清视频的完美支持&#xff0c;能够提供极致的视觉体验。然而&#xff0c;由于其相对较大的文件大小&#xff0c;有时可能不太适合网络传输。此外&#xff0c;部分不支持M2TS的播放设备可能导致一定的兼容性问题。 想要播放m2ts视频&#xff0c;可…

MySQL实战45讲——30答疑文章(二):用动态的观点看加锁

目录 不等号条件里的等值查询 等值查询的过程 怎么看死锁&#xff1f; 怎么看锁等待&#xff1f; update 的例子 小结 上期问题时间 提示 文章摘自林晓斌老师《MySQL实战45讲》&#xff0c;作为笔记而用&#xff0c;故有加一些自己的理解。在第[20]和[21]篇文章中&…

Python基础二

一、变量 在编程中&#xff0c;变量是用来存储数据值的名称。在 Python 中&#xff0c;变量是动态类型的&#xff0c;这意味着你可以将任何类型的数据分配给一个变量&#xff0c;而不需要提前声明变量的类型。 1、全局变量 在函数外部定义的变量是全局变量&#xff0c;可以在程…

cesium-天际线

主要是两个着色器 let postProccessStage new Cesium.PostProcessStage({//unform着色器对象 textureScalefragmentShader:// 声明一个纹理采样器 colorTexture 用于读取纹理颜色uniform sampler2D colorTexture; // 声明一个纹理采样器 depthTexture 用于读取深度纹理unifor…

Python接口自动化之Token详解及应用

以下介绍Token原理及在自动化中的应用。 一、Token基本概念及原理 1.Token作用 为了验证用户登录情况以及减轻服务器的压力&#xff0c;减少频繁的查询数据库&#xff0c;使服务器更加健壮。 2.什么是Token Token是服务端生成的一串字符串&#xff0c;以作客户端进行请求的…

《焦点访谈》上的星火大模型:AI生成春天散文,共绘美好春天

发布 | 大力财经 在今年的全国“两会”上&#xff0c;全国人大代表、科大讯飞董事长刘庆峰提出了关于制定国家《通用人工智能发展规划》的建议&#xff0c;推动我国通用人工智能的发展&#xff0c;以应对全球AI领域的激烈竞争。 刘庆峰在3月6日晚间的《焦点访谈》中表示&#…

简单整理vue-router,路由知识

1.项目中引入 1.1 安装注册 1.2 封装抽离 在main.js中 书写,会造成单个js文件过于臃肿的情况,需要将路由配置部分抽离出来,在src下新建router文件夹,新建index.js文件 import Vue from vue import VueRouter from vue-router import HomeView from ../views/HomeView.vue im…

Elasticsearch:dense vector 数据类型及标量量化

密集向量&#xff08;dense_vector&#xff09;字段类型存储数值的密集向量。 密集向量场主要用于 k 最近邻 (kNN) 搜索。 dense_vector 类型不支持聚合或排序。 默认情况下&#xff0c;你可以基于 element_type 添加一个 dend_vector 字段作为 float 数值数组&#xff1a; …

【中间件】docker的安装

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;中间件 ⛺️稳中求进&#xff0c;晒太阳 .卸载旧版 首先如果系统中已经存在旧的Docker&#xff0c;则先卸载&#xff1a; yum remove docker \docker-client \docker-client-latest \doc…

Web自动化测试学习方向(Selenium)

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

chrome插件webRequest拦截请求并获取post请求体requestBody数据raw内容,解决中文乱码问题

详细使用说明可以看官方文档&#xff1a;https://developer.chrome.com/docs/extensions/reference/api/webRequest?hlzh-cn 拦截操作 想要通过浏览器插件拦截请求的话&#xff0c;需要在manifest.json里面添加webRequet权限&#xff1a; 拦截请求代码放在background.js里面…

Web服务器

Web服务器 1. 阻塞/非阻塞、同步/异步(网络IO)2. Unix/Linux 上的五种IO模型2.1 阻塞 blocking2.2 非阻塞 non-blocking &#xff08;NIO&#xff09;2.3 IO复用&#xff08;IO multiplexing&#xff09;2.4 信号驱动&#xff08;signal-driven&#xff09;2.5 异步&#xff08…