5.26 基于UDP的网络聊天室

需求:

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

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

服务器可以发送系统信息实现模型

模型:

代码:

//chatser.c -- 服务器端实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <time.h>
#include <stdbool.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <unistd.h>
#include <poll.h>#define SER_IP "192.168.2.25"
#define SER_PORT 8888char tm[64];typedef enum msgType{LOGIN,LOGOUT,CHAT,
}msgType;typedef struct usrMsg{msgType type;char usrName[32];char text[1024];
}usrMsg;typedef struct cliNode{char usrName[32];struct sockaddr_in cin;struct cliNode* next;
}cnode_t, *pcnode_t;typedef struct cliHead{unsigned curUsrNum;pcnode_t next;
}chead_t, *pchead_t;const char* getTime();
void createNode(pcnode_t* p, const char* name, const struct sockaddr_in* pcin);
void clinkInit(pchead_t* h);
bool isEmpty(const pchead_t h);
void clinkHeadInsert(pchead_t h, pcnode_t p);
void clinkRemoveByVal(pchead_t h, const struct sockaddr_in* pcin);
void clinkDestory(pchead_t* h);
void printErr(const char* s);int main(int argc, const char *argv[])
{pchead_t h = NULL;clinkInit(&h);int sfd = socket(AF_INET, SOCK_DGRAM, 0);if(-1 == sfd){printErr("socket");return 1;}printf("[%s]main: Socket created(sfd = %d)\n", getTime(), sfd);struct sockaddr_in sin = {.sin_family = AF_INET,.sin_port = htons(SER_PORT),.sin_addr = { inet_addr(SER_IP) },};if(-1 == bind(sfd, (struct sockaddr*)&sin, sizeof(sin))){printErr("bind");return 1;}printf("[%s]main: Success to bind(IP:%s PORT:%hu)\n", getTime(),SER_IP, SER_PORT);struct pollfd pfd[2] = {{ STDIN_FILENO, POLLIN },{ sfd, POLLIN },};struct sockaddr_in cin;socklen_t cin_len = sizeof(cin);char buf[2048] = {};while(1){int ret = poll(pfd, 2, -1);if(-1 == ret){printErr("poll");return 1;}else if(0 == ret){fprintf(stderr, "[%s]poll: Time out\n", getTime());return 1;}if(POLLIN == pfd[0].revents){char input[512] = {};bzero(buf, sizeof(buf));sprintf(buf, "[%s]System:", getTime());fgets(input, sizeof(input), stdin);if(!strcmp(input, "quit\n")){printf("[%s]System: Start to shutdown...\n", getTime());clinkDestory(&h);	break;}if(isEmpty(h)){printf("[%s]System: No user online now\n", getTime());continue;}else{strcat(buf, input);pcnode_t tmp = h->next;while(tmp){sendto(sfd, buf, strlen(buf), 0, (struct sockaddr*)&tmp->cin, sizeof(tmp->cin));tmp = tmp->next;}printf("[%s]System: send msg: %s", getTime(), input);}}if(POLLIN == pfd[1].revents){bzero(buf, sizeof(buf));struct usrMsg msg = {};recvfrom(sfd, &msg, sizeof(msg), 0, (struct sockaddr*)&cin, &cin_len);switch(msg.type){case LOGIN:pcnode_t p = NULL;createNode(&p, msg.usrName, &cin);printf("[%s] %s:%hu has connected\n", getTime(), inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));if(!isEmpty(h)){bzero(buf, sizeof(buf));sprintf(buf, "[%s] %s is online now!\n", getTime(), msg.usrName);pcnode_t tmp = h->next;while(tmp){sendto(sfd, buf, strlen(buf), 0, (struct sockaddr*)&tmp->cin, sizeof(tmp->cin));tmp = tmp->next;}}clinkHeadInsert(h, p);break;case LOGOUT:printf("[%s] %s:%hu has disconnected\n", getTime(), inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));if(!isEmpty(h)){bzero(buf, sizeof(buf));sprintf(buf, "[%s] %s is offline\n", getTime(), msg.usrName);pcnode_t tmp = h->next;while(tmp){sendto(sfd, buf, strlen(buf), 0, (struct sockaddr*)&tmp->cin, sizeof(tmp->cin));tmp = tmp->next;}}clinkRemoveByVal(h, &cin);break;case CHAT:printf("[%s] %s:%hu is chatting\n", getTime(), inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));sprintf(buf, "[%s] %s:\n%s\n", getTime(), msg.usrName, msg.text);pcnode_t tmp = h->next;while(tmp){const char* ip_1 = inet_ntoa(tmp->cin.sin_addr);const char* ip_2 = inet_ntoa(cin.sin_addr);if(!strcmp(ip_1, ip_2) && tmp->cin.sin_port == cin.sin_port){tmp = tmp->next;continue;}sendto(sfd, buf, strlen(buf), 0, (struct sockaddr*)&tmp->cin, sizeof(tmp->cin));tmp = tmp->next;}break;default:fprintf(stderr, "[%s]System: Unknown msg type\n", getTime());break;}}}close(sfd);return 0;
}void printErr(const char* s){fprintf(stderr, "[%s]", getTime());perror(s);
}const char* getTime(){bzero(tm, sizeof(tm));time_t sec;time(&sec);struct tm* loc_tm = localtime(&sec);const char* fmt = "%Y-%m-%d %H:%M:%S";strftime(tm, sizeof(tm), fmt, loc_tm);return tm;
}void createNode(pcnode_t* p, const char* name, const struct sockaddr_in* pcin){if(NULL == p || NULL == name || NULL == pcin){fprintf(stderr, "[%s]createNode: Invalid argument\n", getTime());return;}*p = (pcnode_t)malloc(sizeof(cnode_t));if(NULL == *p){fprintf(stderr, "[%s]createNode: Fail to malloc\n", getTime());return;}else{strcpy((*p)->usrName, name);(*p)->cin = *pcin;(*p)->next = NULL;return;}
};void clinkInit(pchead_t* h){if(NULL == h){fprintf(stderr, "[%s]clinkInit: Invalid argument\n", getTime());return;}*h = (pchead_t)malloc(sizeof(chead_t));if(NULL == *h){fprintf(stderr, "[%s]clinkInit: Fail to malloc\n", getTime());return;}else{(*h)->curUsrNum = 0;(*h)->next = NULL;return;}
}bool isEmpty(const pchead_t h){if(NULL == h){fprintf(stderr, "[%s]isEmpty: Invalid argument\n", getTime());return false;}if(0 == h->curUsrNum)return true;elsereturn false;
}void clinkHeadInsert(pchead_t h, pcnode_t p){if(NULL == h || NULL == p){fprintf(stderr, "[%s]clinkHeadInsert: Invalid argument\n", getTime());return;}else{p->next = h->next;h->next = p;h->curUsrNum++;return;}
}void clinkRemoveByVal(pchead_t h, const struct sockaddr_in* pcin){if(NULL == h || NULL == pcin){fprintf(stderr, "[%s]clinkRemoveByVal: Invalid argument\n", getTime());return;}else if(isEmpty(h))return;else{void* i = h;pcnode_t j = h->next;while(j){const char* ip_1 = inet_ntoa(j->cin.sin_addr);const char* ip_2 = inet_ntoa(pcin->sin_addr);if(!strcmp(ip_1, ip_2) && j->cin.sin_port == pcin->sin_port){pcnode_t tmp = NULL;if(i == h)((pchead_t)i)->next = j->next;else((pcnode_t)i)->next = j->next;tmp = j;j = tmp->next;printf("[%s]clinkRemoveByVal: Cleaning the node[%s:%hu]...\n", getTime(),inet_ntoa(tmp->cin.sin_addr), ntohs(tmp->cin.sin_port));free(tmp);h->curUsrNum--;}else{i = j;j = j ->next;}}}
}void clinkDestory(pchead_t* h){if(NULL == h || NULL == *h){fprintf(stderr, "[%s]clinkDestory: Invalid argument\n", getTime());return;}else{pcnode_t tmp = (*h)->next;while(tmp){printf("[%s]clinkDestory: Cleaning the node[%s:%hu]...\n", getTime(),inet_ntoa(tmp->cin.sin_addr), ntohs(tmp->cin.sin_port));(*h)->next = tmp->next;free(tmp);tmp = (*h)->next;}free(*h);printf("[%s]clinkDestory: Cleaning the head...\n", getTime());*h = NULL;return;}
}
//charcli.c -- 客户端实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/types.h>
#include <poll.h>
#include <sys/socket.h>#define SER_IP "192.168.2.25"
#define SER_PORT 8888
#define CLI_IP "192.168.2.82"char tm[64];typedef enum msgType{LOGIN,LOGOUT,CHAT,
}msgType;typedef struct usrMsg{msgType type;char usrName[32];char text[1024];
}usrMsg;const char* getTime();
void printErr(const char* s);int main(int argc, const char *argv[])
{char usrName[32] = {};puts("Please enter your name: ");fgets(usrName, sizeof(usrName), stdin);usrName[strlen(usrName) - 1] = '\0';printf("Welcome, %s!\n", usrName);int cfd = socket(AF_INET, SOCK_DGRAM, 0);if(-1 == cfd){printErr("socket");return 1;}printf("[%s]main: Socket created(cfd = %d)\n", getTime(), cfd);struct sockaddr_in sin = {.sin_family = AF_INET,.sin_port = htons(SER_PORT),.sin_addr = { inet_addr(SER_IP) },};struct pollfd pfd[2] = {{STDIN_FILENO, POLLIN},{cfd, POLLIN},};struct usrMsg msg = {};msg.type = LOGIN;strcpy(msg.usrName, usrName);sendto(cfd, &msg, sizeof(msg), 0, (struct sockaddr*)&sin, sizeof(sin));printf("[%s]main: Start to login...\n", getTime());while(1){int ret = poll(pfd, 2, -1);if(-1 == ret){printErr("poll");return 1;}else if(0 == ret){fprintf(stderr, "[%s]poll: Time out\n", getTime());return 1;}if(POLLIN == pfd[0].revents){bzero(msg.text, sizeof(msg.text));fgets(msg.text, sizeof(msg.text), stdin);msg.text[strlen(msg.text) - 1] = '\0';if(!strcmp(msg.text, "quit")){msg.type = LOGOUT;sendto(cfd, &msg, sizeof(msg), 0, (struct sockaddr*)&sin, sizeof(sin));break;}msg.type = CHAT;sendto(cfd, &msg, sizeof(msg), 0, (struct sockaddr*)&sin, sizeof(sin));}if(POLLIN == pfd[1].revents){char buf[2048] = {};recv(cfd, buf, sizeof(buf), 0);printf("%s", buf);}}close(cfd);return 0;
}void printErr(const char* s){fprintf(stderr, "[%s]", getTime());perror(s);
}
const char* getTime(){bzero(tm, sizeof(tm));time_t sec;time(&sec);struct tm* loc_tm = localtime(&sec);const char* fmt = "%Y-%m-%d %H:%M:%S";strftime(tm, sizeof(tm), fmt, loc_tm);return tm;
}

效果:

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

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

相关文章

hive初始化失败报错:Error: Duplicate key name ‘PCS_STATS_IDX‘ (state=42000,code=1061)

意思是key name ‘PCS_STATS_IDX’ (state42000,code1061)重复了&#xff0c;问题出在不是第一次初始化&#xff0c;因为我们在hive-site.xml中配置了 javax.jdo.option.ConnectionURL jdbc:mysql://192.168.200.137:3306/metastore?createDatabaseIfNotExisttrue JDBC conne…

JavaSE——类和对象(二)~~封装

目录 一.封装 二.封装扩展之包 三.static成员 四. 代码块 五. 内部类&#xff08;重要&#xff09; 大家好呀&#xff0c;我是北纬&#xff0c;接着上节我们继续讲解Java中关于类和对象的相关知识&#xff0c;今天着重给大家介绍一下关于面向对象程序的特性之一——封装。…

【Linux】常用基础命令 | 搭建云服务器优化环境 | 程序的部署

文章目录 Linux常用命令及搭建环境一、LinuxLinux发行版 1.常用命令1.ls2.cd3.pwd4.touch5.cat6.echo7.vim8.mkdir9.rm10.mv11.cp12.man13.grep14.ps15.netstat 2.搭建Java Web程序的运行环境包管理器1.安装JDK2.安装Tomcat3.安装mysql 3.程序的部署 Linux常用命令及搭建环境 …

有趣的css - 移形换位加载动画

大家好&#xff0c;我是 Just&#xff0c;这里是「设计师工作日常」&#xff0c;今天分享的是一个移形换位动态加载小动效&#xff0c;适用于 app 列表加载&#xff0c;页面加载或者图片懒加载等场景。 最新文章通过公众号「设计师工作日常」发布。 目录 整体效果核心代码html…

2024上海初中生古诗文大会倒计时4个月:单选题真题解析(持续)

现在距离2024年初中生古诗文大会还有4个多月时间&#xff0c;我们继续来看10道选择题真题和详细解析&#xff0c;以下题目截取自我独家制作的在线真题集&#xff0c;都是来自于历届真题&#xff0c;去重、合并后&#xff0c;每道题都有参考答案和解析。 为帮助孩子自测和练习&…

C#基础一

使用Visual Studio 2022&#xff08;VS2022&#xff09;编写C#控制台程序 1. 安装Visual Studio 2022 确保已安装Visual Studio 2022。如果未安装&#xff0c;请从Visual Studio官网下载并安装。 另一篇文章中已经有详细描述&#xff0c;这里就不在细说了。 VisualStudio2022…

【LeetCode】【209】长度最小的子数组(1488字)

文章目录 [toc]题目描述样例输入输出与解释样例1样例2样例3 提示进阶Python实现前缀和二分查找滑动窗口 个人主页&#xff1a;丷从心 系列专栏&#xff1a;LeetCode 刷题指南&#xff1a;LeetCode刷题指南 题目描述 给定一个含有n个正整数的数组和一个正整数target找出该数组…

微信小程序报错:notifyBLECharacteristicValueChange:fail:nodescriptor的解决办法

文章目录 一、发现问题二、分析问题二、解决问题 一、发现问题 微信小程序报错&#xff1a;notifyBLECharacteristicValueChange:fail:nodescriptor 二、分析问题 这个提示有点问题&#xff0c;应该是该Characteristic的Descriptor有问题&#xff0c;而不能说nodescriptor。 …

axios如何传递数组作为参数,后端又如何接收呢????

前端的参数是一个数组。 前端编写&#xff1a; 后端接收&#xff1a;

Iterater迭代器和增强for循环

1、Collection接口遍历元素—Iterator迭代器 看一下下面这张图片&#xff1a;可以看出Collection接口有一个父接口Iterable&#xff0c;Iterable接口有一个iterator()方法&#xff0c;iterator()方法的类型是Iterator迭代器&#xff0c;实际上当我们使用方法时&#xff0c;返回…

Go语言的pprof工具是如何使用的?

文章目录 Go语言的pprof工具详解pprof的使用runtime/pprofnet/http/pprof 快速开始获取采样数据通过pprof工具进行性能分析总结 Go语言的pprof工具详解 Go语言作为一个高性能、高并发的编程语言&#xff0c;对性能优化有着极高的要求。在Go语言的标准库中&#xff0c;pprof是一…

linux 安全 iptables防火墙 (一)

Linux包过滤防火墙概述 Linux 系统的防火墙 &#xff1a;IP信息包过滤系统&#xff0c;它实际上由两个组件netfilter 和 iptables组成。 主要工作在网络层&#xff0c;针对IP数据包。体现在对包内的IP地址、端口、协议等信息的处理上。 两大组件 netfilter内核组件 iptables应…

blender安装cats-blender-plugin-0-19-0插件,导入pmx三维模型

UE5系列文章目录 文章目录 UE5系列文章目录前言一、Blender安装二、cats-blender-plugin-0-19-0插件下载三、下载bmp文件四、在blender2.93中安装cats-blender-plugin-0-19-0插件 前言 blender本身不支持pmx三维模型&#xff0c;需要用到cats-blender-plugin-0-19-0插件。 一…

构建全面的无障碍学习环境:科技之光,照亮学习之旅

在信息与科技日益发展的当下&#xff0c;为所有人群提供一个包容和平等的学习环境显得尤为重要&#xff0c;特别是对于盲人朋友而言&#xff0c;无障碍学习环境的构建成为了一项亟待关注与深化的课题。一款名为“蝙蝠避障”的辅助软件&#xff0c;以其创新的设计理念与实用功能…

Offline RL : Context-Former: Stitching via Latent Conditioned Sequence Modeling

paper 基于HIM的离线RL算法&#xff0c;解决基于序列模型的离线强化学习算法缺乏对序列拼接能力。 Intro 文章提出了ContextFormer&#xff0c;旨在解决决策变换器&#xff08;Decision Transformer, DT&#xff09;在轨迹拼接&#xff08;stitching&#xff09;能力上的不足…

新定义单片机的说明

新定义的官网是https://www.rdsmcu.com/shop/#/,主要经营的是1T系列的51单片机&#xff0c;之前从他们官网上申请了评估板&#xff0c;自己页玩了一段时间&#xff0c;不过玩的不多&#xff0c;特开此专栏记录学习过程&#xff0c;并帮助刚入门的道友快速上手。 我申请的是评估…

DQL(数据查询)

目录 1. DQL概念 2. DQL - 编写顺序 3. 基础查询 3.1 查询多个字段 3.2 字段设置别名 3.3 去除重复记录 3.4 案例 4. 条件查询 4.1 语法 4.2 条件 4.3 案例&#xff1a; 5. 聚合函数 5.1 常见的聚合函数&#xff1a; 5.2 语法 5.3 案例&#xff1a; 6. 分组查…

VScode SSH连接远程服务器报错

一、报错 通过VScode SSH插件远程连接服务器&#xff0c;输入密码后没有连接成功&#xff0c;一直跳出输入密码界面&#xff0c;在输出界面里&#xff0c;一直是Waiting for server log或者是显示Cannot not find minimist 二、处理 &#x1f431;&#xff1a; 这个时候应该…

CTF网络安全大赛web题目:字符?正则?

题目来源于&#xff1a;bugku 题目难度&#xff1a;难 题目描  述: 字符&#xff1f;正则&#xff1f; 题目htmnl源代码&#xff1a; <code><span style"color: #000000"> <span style"color: #0000BB"><?php <br />highl…

类图的六大关系

类图中的六大关系包括&#xff1a;继承关系、实现关系、关联关系、聚合关系、组合关系和依赖关系。 1. 继承关系 继承是一种类与类之间的关系&#xff0c;表示一种泛化和特化的关系。子类继承父类的特性和行为。 class Animal {void eat() {System.out.println("This an…