C++如何实现多人聊天室
发表于:2024-11-12 作者:千家信息网编辑
千家信息网最后更新 2024年11月12日,本篇内容介绍了"C++如何实现多人聊天室"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!UDP服务端代
千家信息网最后更新 2024年11月12日C++如何实现多人聊天室
本篇内容介绍了"C++如何实现多人聊天室"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
UDP
服务端代码:
// Test_Console.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include#include #include #include #include #include using namespace std;#pragma region 全局变量SOCKET server; // 服务端套接字sockaddr_in sai_server; // 服务端信息(ip、端口)// 消息格式struct umsg { int type; // 协议(1:加入 2:退出 3:发消息) char name[64]; // 用户名字 char text[512]; // 文本信息};// 客户端链表typedef struct ucnode { sockaddr_in addr; // 客户端的地址和端口号 umsg msg; // 客户端传来的消息 ucnode* next;} *ucnode_t;#pragma endregion#pragma region 依赖函数// 链表插入数据ucnode* insertNode(ucnode* head, sockaddr_in addr,umsg msg) { ucnode* newNode = new ucnode(); newNode->addr = addr; newNode->msg = msg; ucnode* p = head; if (p == nullptr) { head = newNode; } else { while (p->next != nullptr) { p = p->next; } p->next = newNode; } return head;}// 链表删除数据ucnode* deleteNode(ucnode* head, umsg msg) { ucnode* p = head; if (p == nullptr) { return head; } if (strcmp(p->msg.name, msg.name) == 0){ head = p->next; delete p; return head; } while (p->next != nullptr && strcmp(p->next->msg.name, msg.name) != 0) { p = p->next; } if (p->next == nullptr) { return head; } ucnode* deleteNode = p->next; p->next = deleteNode->next; delete deleteNode; return head;}#pragma endregionint main(){ cout << "我是服务端" << endl; // 初始化 WSA ,激活 socket WSADATA wsaData; if (WSAStartup( MAKEWORD(2, 2), // 规定 socket 版本为 2.2 &wsaData // 接收关于套接字的更多信息 )) { cout << "WSAStartup failed : " << GetLastError() << endl; } // 初始化 socket、服务器信息 server = socket( AF_INET, // IPV4 SOCK_DGRAM, // UDP 0 // 不指定协议 ); sai_server.sin_addr.S_un.S_addr = 0; // IP地址 sai_server.sin_family = AF_INET; // IPV4 sai_server.sin_port = htons(8090); // 传输协议端口 // 本地地址关联套接字 if (bind( server, // 要与本地地址绑定的套接字 (sockaddr*)&sai_server, // 用来接收客户端消息的 sockaddr_in 结构体指针 sizeof(sai_server) )) { cout << "bind failed : " << GetLastError() << endl; WSACleanup(); } // 初始化客户端链表 ucnode* listHead = new ucnode(); listHead->next = nullptr; ucnode* lp = listHead; // 监听消息 while (1) { // 接收来自客户端的消息 umsg msg; int len_client = sizeof(sockaddr); recvfrom( server, // 本地套接字 (char*)&msg, // 存放接收到的消息 sizeof(msg), 0, // 不修改函数调用行为 (sockaddr*)&sai_server, // 接收客户端的IP、端口 &len_client // 接收消息的长度,必须初始化,否则默认为0 收不到消息 ); // sin_addr 转 char[](char[] 转 sin_addr 使用 inet_top) char arr_ip[20]; inet_ntop(AF_INET, &sai_server.sin_addr, arr_ip, 16); // 处理消息(1:用户登录,2:用户退出,3:普通会话) switch (msg.type) { case 1: insertNode(listHead, sai_server, msg); cout << "[" << arr_ip << ":" << ntohs(sai_server.sin_port) << "] " << msg.name << ":" << "---登录---" << endl; break; case 2: deleteNode(listHead, msg); cout << "[" << arr_ip << ":" << ntohs(sai_server.sin_port) << "] " << msg.name << ":" << "---退出---" << endl; break; case 3: cout << "[" << arr_ip << ":" << ntohs(sai_server.sin_port) << "] " << msg.name << ":" << msg.text << endl; // 更新 msg.text lp = listHead; while (lp) { if (strcmp(lp->msg.name, msg.name) == 0) { strncpy(lp->msg.text, msg.text, sizeof(msg.text)); lp->msg.type = msg.type; break; } lp = lp->next; } // 向其他客户端广播(除自己之外) lp = listHead; while (lp) { if (strcmp(lp->msg.name,"") != 0 && strcmp(lp->msg.name, msg.name) != 0) { sendto( server, // 本地套接字 (char*)&msg, // 消息结构体 sizeof(msg), 0, // 不修改函数调用行为 (sockaddr*) & lp->addr, // 目标客户端地址 sizeof(lp->addr) ); } lp = lp->next; } break; } } // 禁用 socket WSACleanup(); getchar(); return 0;}
客户端代码:
// Test_Console_2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include#include #include #include #include #include #include #pragma comment(lib,"ws2_32.lib")using namespace std;#pragma region 全局变量SOCKET client; // 客户端套接字 sockaddr_in sai_client; // 存放客户端地址、端口sockaddr_in sai_server; // 存放服务端发送的消息// 发送和接收的信息体struct umsg { int type; // 协议(1:登录,2:退出,3:发消息) char name[64]; // 用户名字 char text[512]; // 文本};#pragma endregion#pragma region 依赖函数// 监听服务器消息void recvMessage(){ while (1){ umsg msg; int len_server = sizeof(sockaddr); int len = recvfrom(client, (char*)&msg,sizeof(msg),0,(sockaddr*)&sai_server,&len_server); cout << msg.name << ": " << msg.text << endl; }}#pragma endregionint main(){ cout << "我是客户端" << endl; // 初始化 WSA ,激活 socket WSADATA wsaData; if (WSAStartup( MAKEWORD(2, 2), // 规定 socket 版本 &wsaData // 接收 socket 的更多信息 )) { cout << "WSAStartup failed : " << GetLastError() << endl; } // 初始化 socket、客户端信息 client = socket( AF_INET, // IPV4 SOCK_DGRAM, // UDP 0 // 不指定协议 ); sai_client.sin_family = AF_INET; // IPV4 inet_pton(AF_INET, "192.168.1.105", &sai_client.sin_addr); // 服务器 IP地址 sai_client.sin_port = htons(8090); // 端口 // 输入用户名 string name; getline(cin, name); // 发送登录消息 umsg msg; msg.type = 1; strncpy_s(msg.name, sizeof(msg.name), name.c_str(), 64); strncpy_s(msg.text, sizeof(msg.text), "", 512); sendto( client, // 本地套接字 (char*)&msg, // 发送的消息 sizeof(msg), 0, // 不修改函数调用行为 (sockaddr*) & sai_client, // 消息目标 sizeof(sai_client) ); // 接收服务器消息 HANDLE h_recvMes = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)recvMessage, 0, 0, 0); if (!h_recvMes) { cout << "CreateThread failed :" << GetLastError() << endl; } // 发送消息 while (1) { string content; getline(cin, content); // 如果是退出消息 if (content == "quit") { msg.type = 2; sendto(client, (char*)&msg, sizeof msg, 0, (struct sockaddr*) & sai_client, sizeof(sai_client)); closesocket(client); WSACleanup(); return 0; } // 如果是会话消息 msg.type = 3; strncpy_s(msg.text, sizeof(msg.text), content.c_str(), 512); sendto( client, // 本地套接字 (char*)&msg, // 要发送的消息 sizeof(msg), 0, // 不修改函数调用行为 (sockaddr*) & sai_client, // 发送目标 sizeof(sai_client) ); } getchar(); return 0;}
效果图:
TCP
服务器代码:
// Test_Console.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include#include #include #include #include #include using namespace std;#pragma region 全局变量SOCKET server; // 本地套接字sockaddr_in sai_server; // 存放服务器IP、端口// 消息格式struct umsg { int type; // 协议(1:登录,2:退出,3:发消息) char name[64]; // 用户名字 char text[512]; // 文本信息};// 客户端信息struct clientInfo { SOCKET client; sockaddr_in saddr; umsg msg;};// 客户端链表typedef struct ucnode { clientInfo cInfo; ucnode* next;} *ucnode_t;ucnode* listHead; // 客户端链表头ucnode* lp; // 客户端链表指针#pragma endregion#pragma region 依赖函数// 链表插入数据ucnode* insertNode(ucnode* head,SOCKET client, sockaddr_in addr, umsg msg) { ucnode* newNode = new ucnode(); newNode->cInfo.client = client; newNode->cInfo.saddr = addr; newNode->cInfo.msg = msg; ucnode* p = head; if (p == nullptr) { head = newNode; } else { while (p->next != nullptr) { p = p->next; } p->next = newNode; } return head;}// 链表删除数据ucnode* deleteNode(ucnode* head, SOCKET client) { ucnode* p = head; if (p == nullptr) { return head; } if (p->cInfo.client == client) { head = p->next; delete p; return head; } while (p->next != nullptr && p->next->cInfo.client != client) { p = p->next; } if (p->next == nullptr) { return head; } ucnode* deleteNode = p->next; p->next = deleteNode->next; delete deleteNode; return head;}// 接收客户端消息(某个)void recvMessage(PVOID pParam) { clientInfo* cInfo = (clientInfo*)pParam; while (1) { // 接收来自客户端的消息 umsg msg; int len_client = sizeof(sockaddr); int ret_recv = recv( cInfo->client, // 本地套接字 (char*)&msg, // 存放接收的消息 sizeof(msg), // 消息大小 0 // 不修改函数调用行为 ); if (ret_recv <= 0) { cout << msg.name << "断开连接: " << GetLastError() << endl; break; } cInfo->msg = msg; // sin_addr 转 char[](char[] 转 sin_addr 使用 inet_top) char arr_ip[20]; inet_ntop(AF_INET, &cInfo->saddr.sin_addr, arr_ip, 16); // 处理消息(1:登录,2:退出,3:会话) switch (cInfo->msg.type) { case 1: // 插入数据到链表 insertNode(listHead,cInfo->client, cInfo->saddr,cInfo->msg); // 打印消息 cout << "[" << arr_ip << ":" << ntohs(cInfo->saddr.sin_port) << "] " << msg.name << ":" << "---登录---" << endl; break; case 2: // 从链表删除数据 deleteNode(listHead, /*cInfo->msg*/cInfo->client); // 打印消息 cout << "[" << arr_ip << ":" << ntohs(cInfo->saddr.sin_port) << "] " << msg.name << ":" << "---退出---" << endl; break; case 3: // 打印消息 cout << "[" << arr_ip << ":" << ntohs(cInfo->saddr.sin_port) << "] " << msg.name << ":" << cInfo->msg.text << endl; // 向其他客户端广播(除自己之外) lp = listHead; while (lp) { if (strcmp(lp->cInfo.msg.name, "") != 0 && strcmp(lp->cInfo.msg.name, cInfo->msg.name) != 0) { send( lp->cInfo.client, // 本地套接字 (char*)&cInfo->msg, // 发送的消息 sizeof(cInfo->msg), // 消息大小 0 // 不指定调用方式 ); int error_send = GetLastError(); if (error_send != 0) { cout << "send failed:" << error_send << endl; } } lp = lp->next; } break; } }}#pragma endregionint main(){ cout << "我是服务端" << endl; // 初始化 WSA ,激活 socket WSADATA wsaData; if (WSAStartup( MAKEWORD(2, 2), // 规定 socket 版本为 2.2 &wsaData // 接收关于套接字的更多信息 )) { cout << "WSAStartup failed : " << GetLastError() << endl; } // 初始化 socket、服务器信息 server = socket( AF_INET, // IPV4 SOCK_STREAM, // TCP 0 // 不指定协议 ); sai_server.sin_addr.S_un.S_addr = 0; // IP地址 sai_server.sin_family = AF_INET; // IPV4 sai_server.sin_port = htons(8090); // 传输协议端口 // 本地地址关联套接字 if (bind( server, // 要与本地地址绑定的套接字 (sockaddr*)&sai_server, // 用来接收客户端消息的 sockaddr_in 结构体指针 sizeof(sai_server) )) { cout << "bind failed : " << GetLastError() << endl; WSACleanup(); } // 套接字进入监听状态 listen( server, // 本地套接字 SOMAXCONN // 挂起连接队列的最大长度,SOMAXCONN:最大合理值 ); // 初始化客户端链表 listHead = new ucnode(); listHead->next = nullptr; lp = listHead; // 接收消息 while (1) { // 接收登录消息(首次连接是触发,之后发送消息不触发) clientInfo* cInfo = new clientInfo(); int len_client = sizeof(sockaddr); cInfo->client = accept(server, (sockaddr*) &cInfo->saddr, &len_client); if (GetLastError() != 0) { continue; } // 接收登录者的消息(每个客户端对应一个线程) HANDLE h_recvMes = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)recvMessage, cInfo, 0, 0); if (!h_recvMes) { cout << "CreateThread failed :" << GetLastError() << endl; } } // 禁用 socket WSACleanup(); getchar(); return 0;}
客户端代码:
// Test_Console_2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include#include #include #include #include #include #include #pragma comment(lib,"ws2_32.lib")using namespace std;#pragma region 全局变量SOCKET client; // 本地套接字sockaddr_in sai_client; // 存放客户端IP地址、端口// 消息格式struct umsg { int type; // 协议(1:登录,2:退出,3:发消息) char name[64]; // 用户名字 char text[512]; // 文本};#pragma endregion#pragma region 依赖函数// 监听服务器消息void recvMessage(){ while (1){ umsg msg; int ret_recv = recv( client, // 本地套接字 (char*)&msg, // 存放接收的消息 sizeof(msg), // 消息大小 0 // 不指定调用方式 ); if (ret_recv <= 0) { cout << "recv failed: " << GetLastError() << endl; break; } // 打印消息 cout << msg.name << ": " << msg.text << endl; }}#pragma endregionint main(){ cout << "我是客户端" << endl; // 初始化 WSA ,激活 socket WSADATA wsaData; if (WSAStartup( MAKEWORD(2, 2), // 规定 socket 版本 &wsaData // 接收 socket 的更多信息 )) { cout << "WSAStartup failed : " << GetLastError() << endl; } // 初始化 socket、客户端信息 client = socket( AF_INET, // IPV4 SOCK_STREAM, // TCP 0 // 不指定协议 ); sai_client.sin_family = AF_INET; // IPV4 inet_pton(AF_INET, "192.168.1.100", &sai_client.sin_addr); // 服务器 IP地址 sai_client.sin_port = htons(8090); // 端口 // 连接服务器 int ret_connect = connect( client, // 本地套接字 (sockaddr*) &sai_client, // 目标 sizeof(sai_client) );if (ret_connect != 0) { cout << "connect failed:" << GetLastError() << endl; } // 输入用户名 umsg msg; msg.type = 1; string name; getline(cin, name); strncpy_s(msg.name, sizeof(msg.name), name.c_str(), 64); strncpy_s(msg.text, sizeof(msg.text), "", 512); // 发送登录消息 send( client, // 本地套接字 (char*)&msg, // 发送的消息 sizeof(msg), // 消息大小 0 // 不指定调用方式 ); int error_send = GetLastError(); if (error_send != 0) { cout << "send failed:" << error_send << endl; } // 接收服务器消息 HANDLE h_recvMes = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)recvMessage, 0, 0, 0); if (!h_recvMes) { cout << "CreateThread failed :" << GetLastError() << endl; } // 发送消息 while (1) { string content; getline(cin, content); // 退出消息 if (content == "quit") { msg.type = 2; send( client, // 本地套接字 (char*)&msg, // 发送的消息 sizeof(msg), // 消息大小 0 // 不指定调用方式 ); error_send = GetLastError(); if (error_send != 0) { cout << "send failed:" << error_send << endl; } closesocket(client); WSACleanup(); return 0; } // 会话消息 msg.type = 3; strncpy_s(msg.text, sizeof(msg.text), content.c_str(), 512); send( client, // 本体套接字 (char*)&msg, // 发送的消息 sizeof(msg), // 消息大小 0 // 不指定调用方式 ); error_send = GetLastError(); if (error_send != 0) { cout << "send failed:" << error_send << endl; } } getchar(); return 0;}
效果图:
"C++如何实现多人聊天室"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!
消息
客户
套接字
客户端
服务
信息
地址
函数
服务器
登录
端口
用户
大小
更多
数据
方式
行为
代码
全局
变量
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
数据库的导入导出
购买阿里云ecs服务器
mysql怎么连数据库
阿里访客网络安全吗
裸金属服务器需要开启dhcp吗
服务器开发 简历
湖南人与软件开发
火车头修改数据库密码
河南贸易进口软件代理服务器
服务器硬盘粉色
区块链依靠网络技术
网络安全视频直播活动
阿尔戈兽数码兽数据库
seer数据库数据筛选
数据库url设置时区代码
常用法律数据库
公安网络安全审计中移铁通
蓝泰源老是服务器忙
金融科技移动互联网
墨子推演数据库设计
闵行区网络技术咨询服务哪个好
数据库 网站 模板
易语言读写cdb数据库
自己做服务器哪个最便宜
sqlite可以放在服务器上吗
电力系统网络安全检查报告
恩施土家族苗族自治州软件开发
贵州三石网络技术有限公司
做软件开发买微星笔记本
网络安全三级等保复测分数