day7-网络编程

news2024/11/26 0:45:20

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.coloradmin.cn/o/1494215.html

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

相关文章

2024-3-6-数据库作业

作业&#xff1a;数据库操作的增、删、改完成 &#xff08;目前只能实现静态管理&#xff09; 源代码&#xff1a; #include <myhead.h> void do_add(sqlite3 *ppDb) {char *errmsg NULL;char sql[128] "insert into Worker values(1001,小张,15000);";//…

《中学综合素质》黄金卷(二)

2.对下图漫画描述不正确的是&#xff08;A &#xff09;。 A.忽视了平等待生 B.忽视了学生的个性发展 C.忽视了学生的差异性 D.违背了素质教育观 8.“任何组织或者个人不得隐匿、毁弃、非法删除未成年人的信件、日记、电子邮件或者其 他网络通讯内容”&#xff0c;对照《中华…

离散数学例题——3.计数和集合论(集合与二元关系)

幂集与子集数目 集合运算 集合的证明 集合构建符号证明 用集合成员表证明 用集合运算定律证明 无限集、等势、无限可数集和无限不可数集的基数 关系的定义、个数 关系的表示 关系的运算 使用矩阵运算实现关系的运算 关系的证明 关系的性质 自反性和反自反性&#xff08;矩阵对…

大唐杯学习笔记:Day5

1.1 小区搜索 搜索流程 PLMN选择 自动模式&#xff1a;UE根据NAS的请求或自主地向NAS报告可用的PLMN 手动模式&#xff1a;通过手动选择一个可用的VPLMN获取正常服务 频点选择 5G NR中,3GPP主要指定了两个频率范围,一个是6GHZ以下,另一个是毫米波,分别称之为FR1和FR2。 N…

CorelDRAW Graphics Suite2024订阅版费用与永久版的区别

CorelDRAW Graphics Suite的订阅版是一种按周期付费的软件使用模式&#xff0c;允许用户以一定的费用在一段时间内访问和使用CorelDRAW Graphics Suite的全部或部分功能。这种模式通常不涉及软件的所有权转让&#xff0c;而是提供使用权。 CDR2024绿色版下载链接: https://pan…

显示高考天数倒计时——vba实现

以下代码实现高考倒计时&#xff1a; Sub 高考倒计时() 高考日期 CDate("06,07," & Year(Date)) If Date > 高考日期 Then高考日期 CDate("06-07-" & Year(Date) 1) End If 年月日 Year(Date) & "年" & Month(Date) &am…

【OpenGL的着色器03】内置变量和函数(gl_Position等)

目录 一、说明 二、着色器的变量 2.1 着色器变量 2.2 着色器内置变量 三、最常见内置变量使用范例 3.1 常见着色器变量 3.2 示例1&#xff1a; gl_PointSize 3.3 示例2&#xff1a;gl_Position 3.4 gl_FragColor 3.5 渲染点片元坐标gl_PointCoord 3.6 gl_PointCoo…

如何阅读“计算机界三大计算思维神书”之一 ——SICP

《计算机程序的构造和解释》&#xff08;Structure and Interpretation of Computer Programs&#xff0c;简记为SICP&#xff09;是MIT的基础课教材&#xff0c;出版后引起计算机教育界的广泛关注&#xff0c;对推动全世界大学计算机科学技术教育的发展和成熟产生了很大影响。…

【ESP32 IDF】I2C层次结构、I2C协议

文章目录 前言一、I2C的结构层次1.1 怎样在两个设备之间传输数据1.2 I2C如何传输数据1.3 硬件框图1.4 软件层次 二、IIC协议2.1 硬件连接2.2 I2C 总线的概念2.3 传输数据类比2.3 I2C信号2.4 I2C数据的含义 总结 前言 I2C&#xff08;Inter-Integrated Circuit&#xff09;是一…

可访问性使命:Facebook构建无障碍社交空间

在当今数字化时代&#xff0c;社交媒体已成为人们日常生活的重要组成部分&#xff0c;而Facebook作为全球最大的社交平台之一&#xff0c;其使命不仅在于连接世界&#xff0c;还在于构建一个无障碍的社交空间&#xff0c;让每个人都能参与其中。本文将深入探讨Facebook在可访问…

Flask入门三(Flask-session的使用、数据库链接池、wtforms、Flask定制命令、Flask-Cache)

文章目录 一、Flask-session使用1.使用方式一2.使用方式二3.读RedisSessionInterface源码4.flask-session补充 二、数据库连接池1.flask中使用mysql2.上述问题解决 使用数据库连接池1.第三方数据库连接池2.操作数据库不带池版3.池版和非池版压测 三、wtforms四、Flask定制命令1…

2024作品集流行封面设计技巧

本期不是关于如何安排作品集&#xff0c;而是关于目前国内市场上流行的作品集封面风格有哪些&#xff1f;如何实现&#xff1f;今天给大家带来了 5 种作品集设计风格&#xff0c;毛玻璃、弥散光、3D、插画、其他&#xff0c;一起往下看吧&#xff01; 毛玻璃 目前许多设计师都…

map和set(一)——关联式容器的常用接口使用及区别

一、关联式容器 在初阶阶段&#xff0c;我们已经接触过STL中的部分容器&#xff0c;比如&#xff1a;vector、list、deque、forward_list(C11)等&#xff0c;这些容器统称为序列式容器&#xff0c;因为其底层为线性序列的数据结构&#xff0c;里面 、存储的是元素本身。 那什么…

基于ACM32 MCU的两轮车充电桩方案,打造高效安全的电池管理

随着城市化进程的加快、人们生活水平的提高和节能环保理念的普及&#xff0c;越来越多的人选择了电动车作为代步工具&#xff0c;而两轮电动车的出行半径较短&#xff0c;需要频繁充电&#xff0c;因此在城市中设置两轮车充电桩就非常有必要了。城市中的充电桩不仅能解决两轮车…

NFTScan :什么是 ERC-404?深入解读 NFT 协议的未来

上月初&#xff0c;ERC-404 成为最首要热门的话题&#xff0c;ERC-404 是由 Pandora 团队在 2 月初为创作者和开发者等开源的实验性代币标准&#xff0c;其混合 ERC-20 / ERC-721 实现&#xff0c;具有原生流动性和碎片化等特点。伴随着早期的发展&#xff0c;越来越多参与者开…

Java基于微信小程序的旅游出行必备小程序,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

钡铼技术R40工业路由器连接智慧交通助力城市智慧化建设

随着信息技术与交通行业的深度融合&#xff0c;智慧交通作为智慧城市的重要组成部分&#xff0c;正在全球范围内加速推进。在此进程中&#xff0c;钡铼技术推出的R40工业路由器以其独特的4G WiFi一体化设计&#xff0c;成为连接智慧交通各环节&#xff0c;助力城市智慧化建设的…

一文看懂 | 机器视觉前景

机器视觉概述&#xff1a;机器视觉是人工智能发展中的一个重要分支&#xff0c;其主要目标是用机器替代人眼进行测量和判断。 机器视觉系统通过图像摄取装置将目标转换成图像信号&#xff0c;然后传送给专用的图像处理系统&#xff0c;最终得到目标的形态信息。 全球机器视觉…

『python爬虫』ip代理池使用 协采云 账密模式(保姆级图文)

目录 实现效果实现思路代码示例总结 欢迎关注 『python爬虫』 专栏&#xff0c;持续更新中 欢迎关注 『python爬虫』 专栏&#xff0c;持续更新中 实现效果 在官网原版demo基础上小改了一下,修正了接口错误(把2023改成2024就可以了),原版demo只能测试单个ip,我这里批量测试所有…

项目管理软件大比拼:2024年推荐的9款软件一览

能够有效利用团队的力量并将其转化为切实解决方案的公司更有可能保持领先地位。项目管理软件是可以帮助组织实现这一目标的强大工具。本文将探讨项目管理软件的功能&#xff0c;并为大家介绍9款项目管理软件&#xff0c;为您的企业选择正确的软件时需要考虑的因素。 项目管理软…