坐牢第二十七天(聊天室)

news2024/9/20 20:35:06

基于UDP的网络聊天室

一.项目需求:

1.如果有用户登录,其他用户可以收到这个人的登录信息

2.如果有人发送信息,其他用户可以收到这个人的群聊信息

3.如果有人下线,其他用户可以收到这个人的下线信息

4.服务器可以发送系统信息

二.代码 

udp.h

#ifndef UDP_H
#define UDP_H
#include <myhead.h>
#define SER_PORT 8888           // 服务器端口号
#define SER_IP "192.168.0.105" // 服务器ip地址
#define CLI_PORT 5555          // 客户端端口号
#define CLI_IP "192.168.0.105" // 客户端地址
//枚举
enum type_t
{
    Login,
    Chat,
    Quit,
};
typedef struct MSG
{
    char type;//Login名字  Chat内容 Quit退出  //内容编号
    char name[32];//名字
    char text[128];//内容
}msg_t;
typedef struct NODE//链表
{
    struct sockaddr_in cin;
    struct NODE *next;
}Node,*Nodeptr;
//创建头节点函数
Nodeptr create();
//登录的函数
//功能:
//1.将新登录的用户转发给所有已经登录的用户(遍历链表发送谁登录的消息)
//2.创建新节点来保存新登录用户的信息,链接到链表尾就可以
void do_login(int sockfd,msg_t msg,Nodeptr p,struct sockaddr_in cin);
//群聊的函数
//功能:将客户端发来的聊天内容转发给所有已登录的用户,除了发送聊天内容的用户以外
void do_chat(int sockfd,msg_t msg,Nodeptr p,struct sockaddr_in cin);
//退出函数
//功能:
//1.将谁退出的消息转发给i所有用户
//2.将链表中保存这个推出的用户信息的节点删除
void do_quit(int sockfd,msg_t msg,Nodeptr p,struct sockaddr_in cin);
#endif 

udp.c

#include "udp.h"
// 定义创建头节点函数
Nodeptr create()
{
    Nodeptr p = (Nodeptr)malloc(sizeof(Node));
    if (p == NULL)
    {
        perror("malloc error");
        return NULL;
    }
    p->next = NULL;
    return p;
}
// 定义登录的函数
void do_login(int sockfd, msg_t msg, Nodeptr p, struct sockaddr_in cin)
{
    sprintf(msg.text, "%s 以上线", msg.name);
    while (p->next != NULL)
    {
        p = p->next;
        sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
    }
    Nodeptr new = (Nodeptr)malloc(sizeof(Node));
    // 初始化
    new->cin = cin;
    new->next = NULL;
    // 链接到链表尾
    p->next = new;
    return;
}
// 定义群聊的函数
void do_chat(int sockfd, msg_t msg, Nodeptr p, struct sockaddr_in cin)
{
    // 遍历链表
    while (p->next != NULL)
    {
        p = p->next;

        if (memcmp(&(p->cin), &cin,sizeof(cin))!= 0)
        {
            sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
        }
    }
    return;
}
// 定义退出函数
void do_quit(int sockfd, msg_t msg, Nodeptr p, struct sockaddr_in cin)
{
    sprintf(msg.text, "%s 以下线", msg.name);
    while (p->next != NULL)
    {
        if (memcmp(&(p->cin), &cin,sizeof(cin)) == 0)
        {
            Nodeptr q = NULL;
            q = p->next;
            p->next = q->next;
            free(q);
            q = NULL;
        }
        else
        {
            p = p->next;
            sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
        }
    }
    return;
}

sen.c

// 服务器
#include "udp.h"
int main(int argc, char const *argv[])
{
    // 创建UDP套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("socket error");
        exit(-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);
   
    // 定义保存客户端网络信息的结构体
    struct sockaddr_in cin;
    cin.sin_family = AF_INET;
    cin.sin_port = htons(CLI_PORT);
    cin.sin_addr.s_addr = inet_addr(CLI_IP);
    socklen_t len = sizeof(cin);
    // 绑定套接字和服务器网络信息的结构体
    bind(sockfd, (struct sockaddr *)&sin, sizeof(sin));
    printf("绑定成功!\n");
    msg_t msg;
    Nodeptr p = create();
    char s[20]="";
    while (1)
    {
        if (recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, &len) < 0)
        {
            perror("recvfrom error");
            return -1;
        }
        if (msg.type == Login)
        {
            strcpy(msg.text, "以上线");
            printf("ip:%s pord:%d name:%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), msg.name);
            printf("状态:%s\n", msg.text);
            //调用登录函数
            do_login(sockfd, msg, p, cin);
        }
        else if (msg.type == Chat)
        {
            //调用群聊函数
            do_chat(sockfd, msg, p, cin);
        }
        else if (msg.type == Quit)
        {
            strcpy(msg.text, "以下线");
            printf("ip:%s pord:%d name:%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), msg.name);
            printf("状态:%s\n", msg.text);
            //调用退出函数
            do_quit(sockfd, msg, p, cin);
        }
    }
    close(sockfd);
    return 0;
}

rec.c

// 客户端
#include "udp.h"
int main(int argc, char const *argv[])
{
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("socket error");
        exit(-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);
    socklen_t len = sizeof(sin);
    msg_t msg;
    // 先执行登录操作
    printf("请登录:\n");
    msg.type = Login;
    printf("请输入用户名:");
    fgets(msg.name, 32, stdin);
    msg.name[strlen(msg.name) - 1] = 0;
    // 发送登录消息
    if (sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&sin, len) < 0)
    {
        perror("sendto err");
        exit(-1);
    }
    //创建多进程
    pid_t pid = fork();
    if (pid < 0)
    {
        perror("fork error");
        exit(-1);
    }
    else if (pid == 0)
    {
        while (1)
        {
            if (recvfrom(sockfd, &msg, sizeof(msg), 0, NULL, NULL) < 0)
            {
                perror("recvfrom error");
                return -1;
            }
            printf("[%s]:%s\n", msg.name, msg.text);
        }
    }
    else
    {
        while (1)
        {
            fgets(msg.text, sizeof(msg.text), stdin);
            msg.text[strlen(msg.text) - 1] = 0;
            if (strcmp(msg.text, "quit") == 0)
            {
                msg.type = Quit;
                sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&sin, len);
                kill(pid, SIGKILL);
                wait(NULL);
                exit(EXIT_SUCCESS);
            }
            else
            {
                msg.type = Chat;
            }
            // 发送消息
            sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&sin, len);
        }
    }
    close(sockfd);
    return 0;
}

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

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

相关文章

idea 遇到依赖引入失败问题

在引入 aspects 的相关依赖时&#xff0c;没有找到这个版本 <dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.0-M2</version> </dependency> 第一次尝试&#xff…

C++编程:生产者-消费者模型中条件变量的使用问题及优化方案

文章目录 0. 引言1. 生产者-消费者模型简介1.1 示例代码1.2 为什么必须加锁&#xff1f; 2. 上述代码存在的问题2.1 信号丢失2.2 锁的作用范围2.3 竞态条件 3. 优化方案3.1 使用两个条件变量3.2 扩展锁的作用域3.3 使用原子操作3.4 使用无锁队列 4. 底层实现与深入探讨5. 流程图…

『 C++ 』IO流

文章目录 IO流概述iostream 的标准对象C流和C标准库I/O函数的同步 sync_with_stdiofstream 文件流文件流的打开标志二进制读写二进制读写的浅拷贝问题文本读写 字符串流注意 IO流概述 流是指数据的有序传输序列,路表示数据从一个地方流向另一个地方的过程,流可以是输入流也可以…

欧盟新规:苹果App Store开发者需公开联系方式,透明度提升还是隐私挑战?

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 随着数字经济的蓬勃发展&#xff0c;欧盟对数字服务的监管也在不断加强。最近&#xff0c;苹果公司宣布了一项针对欧盟App Store的新政策&#…

Lesson 67 The weekend

Lesson 67 The weekend 词汇 greengrocer 菜市场 构成&#xff1a;green n. 绿色的    grocer n. 食杂店&#xff0c;小卖店 商店词汇&#xff1a;shop n. 商店      store n. 小店      market n. 市场      super market 超市      Sunday market 二…

Codeforces Round 949 (Div. 2) C.D构造和E题

C题链接 D题链接 E题链接 C题思路&#xff1a; 我们设相邻的两个-1的位置是的值是l和r&#xff0c;他们直接的距离是d(也就是r的下标减l的下标)。 思路1&#xff1a;直接模拟操作&#xff0c;看所有操作里是否有合法操作。 比如1 -1 -1 -1 -1 -1 7. 容易想到1*213,3*217&a…

psychopy 中文语义相关判断任务实验设计

参考文献&#xff1a; [石如彬, 谢久书, 杨梦情, & 王瑞明. (2022). 语言和情境对具体概念感知运动仿真的影响. 心理学报, 54(6), 583–594. https://doi.org/10.3724/SP.J.1041.2022.00583] 2.2.4实验1。 演示效果 按下“上方向键” 按F或J 反馈信息&#xff1a; 实验步骤…

C#中的S7协议

S7协议-S7COMM S7COMM 进行写 CTOP->PDU type已知枚举值 0X0E连接请求0x0d连接确认0x08断开请求0x0c断开确认0x05拒绝访问0x01加急数据0x02加急数据确认0x04用户数据0x07TPDU错误0x0f数据传输 S7Header->ROSCTR已知枚举值 0X01JOB REQUEST。主站发送请求0x02Ack。从站…

jmeter压测websocket

1、jmeter安装websocket插件 下载地址 pjtr / JMeter WebSocket Samplers / Downloads — Bitbucket 下载之后&#xff0c;放到lib/ext文件夹下&#xff0c;重启jmeter即可&#xff0c;看到下图这些证明插件安装成功 2、脚本 新建websocket request-response sampler

day05-SpringBootWeb请求响应学习笔记

上面说过&#xff0c;浏览器向服务端发送请求&#xff0c;服务端会给浏览器发送出响应&#xff0c;无论是哪种&#xff0c;都包含三部分。这一章&#xff0c;依旧围绕这部分内容 请求 Postman 由于前后端分离&#xff0c;对我们后端技术人员来讲&#xff0c;在开发过程中&…

SpringBoot——整合Swagger

目录 Swagger Swagger工具集 Swagger注解 项目总结 新建SpringBoot项目 pom.xml Swagger2Config配置类 User实体类 UserController控制器 项目测试 添加用户 修改用户 查询用户 删除用户 Swagger Swagger是一款基于RESTful接口的用于文档在线自动生成和功能测试的开…

揭开虚拟与现实的帷幕:二进制世界与道

本章将带领读者进入一个结合科学与哲学的思维世界&#xff0c;从一个全新的视角探讨二进制世界的概念&#xff0c;结合超弦理论和老子的“道”哲学&#xff0c;深入理解计算机底层的运行原理及其与宇宙本质的联系。通过回顾经典电影《黑客帝国》以及最新的人工智能发展&#xf…

Android经典实战之Kotlin 2.0 迁移指南:全方位优化与新特性解析

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 Kotlin 2.0 迁移指南&#xff1a;开发者如何迎接新时代 Kotlin 2.0&#xff0c;这个备受期待的版本&#xff0c;终于在 JetBrains 的精心打磨下…

前端各种文本文件预览 文本编辑excel预览编辑 pdf预览word预览 excel下载pdf下载word下载

前端各种文本文件预览 文本编辑excel预览编辑 pdf预览word预览 excel下载pdf下载word下载 各种文本文件预览&#xff08;pdf, xlsx, docx, cpp, java, sql, py, vue, html, js, json, css, xml, rust, md, txt, log, fa, fasta, tsv, csv 等各种文本文件&#xff09; 其中 除p…

【LeetCode Cookbook(C++ 描述)】一刷二叉树综合(上)

目录 LeetCode #226&#xff1a;Invert Binary Tree 翻转二叉树「遍历」「分而治之」广度优先搜索&#xff1a;层序遍历 LeetCode #101&#xff1a;Symmetric Tree 对称二叉树递归法迭代法 LeetCode #100&#xff1a;Same Tree 相同的树递归法迭代法 LeetCode #559&#xff1a;…

万能钥匙:解锁 C++ 模板的无限可能

1.泛型编程 1.1:交换两个数(C语言) 1.2:交换两个数(C) 1.3:泛型编程 2:函数模板 2.1:函数模板的概念 2.2:函数模板的格式 ​编辑 2.3:函数模板的原理 2.4:模板的实例化 2.4.1:隐式实例化 2.4.2:显式实例化:在函数名后的<>中指定模板参数的实际类型. 2.4.2.1…

Unidbg使用指南

Unidbg使用指南 简介使用Unidbg补环境仅含C语言C调用 Java 实操——车智赢在unidbg实现执行so中的方法附——关于引用数据类型的转换附——静态注册和动态注册模板静态注册动态注册 现在很多的app使用了so加密&#xff0c;以后会越来越多。爬虫工程师可能会直接逆向app&#xf…

黑马前端——days09_css

案例 1 页面框架文件 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compati…

Ubuntu20.04如何安装配置JDK

资源准备 官方下载地址&#xff08;根据自己的系统版本选择不同版本进行下载即可&#xff09;&#xff1a;Java Downloads | Oracle 如无特殊需要可直接移步至下方JDK1.8安装包 https://download.csdn.net/download/qq_43439214/89646731 安装步骤 创建Java目录 sudo mkdir …

jmeter安装及环境变量配置、Jmeter目录介绍和界面详解

一 JMeter简介 Apache JMeter是100%纯JAVA桌面应用程序&#xff0c;被设计为用于测试客户端/服务端结构的软件(例如web应用程序)。它可以用来测试静态和动态资源的性能&#xff0c;例如&#xff1a;静态文件&#xff0c;Java Servlet,CGI Scripts,Java Object,数据库和FTP服务器…