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常用命令及搭建环境 …

贪心算法简单介绍

贪心算法是一种在每一步选择中都采取当前状态下最优或最优近似的选择&#xff0c;以期望最终得到全局最优解的算法。贪心算法并不总能得到全局最优解&#xff0c;但在某些问题上&#xff0c;它可以得到全局最优解&#xff0c;并且比动态规划等其他方法更为简单和高效。 贪心算…

Python库之Scrapy的简介、安装、使用方法详细攻略

Python库之Scrapy的简介、安装、使用方法详细攻略 简介 Scrapy是一个快速的、高层次的web抓取和web抓取框架&#xff0c;用于抓取网站数据并从页面中提取结构化的数据。Scrapy用途广泛&#xff0c;可以用于数据挖掘、信息处理或存储历史数据&#xff0c;以及各种其他用途。 …

【AMS】Android 8.0+ 绕开启动后台Service限制

一、背景 应客户要求,需要在开机时,拉起应用A。但因为开机时,同时被拉起的应用过多,导致Launcher在开机那一刻较为卡顿。为解决这一问题,采取了延迟拉起的做法。在开机后,延迟一定时间,由系统服务,拉起应用A。 于是乎,就出现这么个报错: Not allowed to start ser…

vue3、vuex和vue-router入门指南

Vue 3、Vuex 和 Vue Router 都是 Vue.js 生态系统中非常有用的库。它们各自在 Vue.js 应用程序中扮演着重要的角色&#xff1a;Vue 3 是核心框架&#xff0c;Vuex 用于状态管理&#xff0c;而 Vue Router 用于路由管理。下面是如何在 Vue 3 项目中使用这些库的简要说明。 创建…

有趣的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找出该数组…

Effective C++(2)

文章目录 2. 构造、析构、赋值运算条款05&#xff1a;了解C默默编写并调用哪些函数条款06&#xff1a;若不想使用编译器自动生成的函数&#xff0c;就该明确拒绝条款07&#xff1a;为多态基类声明virtual析构函数条款08&#xff1a;别让异常逃离析构函数条款09&#xff1a;绝不…

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

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

web前端之解决img元素组件自有高度的问题

MENU 前言解决办法vertical-align 前言 在HTML和CSS中&#xff0c;img元素默认是行内元素(inline element)&#xff0c;类似于文本。由于文本有基线(baseline)&#xff0c;所以即使是空白的img元素也会占据一定的高度&#xff0c;以便使基线对齐。 解决办法 要解决这个问题&…

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;以其创新的设计理念与实用功能…