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.pswp.cn/bicheng/15178.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/15178.shtml
英文地址,請注明出處:http://en.pswp.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;以其創新的設計理念與實用功能…