聊天室(C++客户端+Pyhton服务器)3.群功能添加
创建群
数据库 group_table(user, name)
grpuser_table(grpname,user)
按下添加群按钮
// 创建群组
void CUserDialog::OnBnClickedCrtgrp()
{
// 1. 获取群的名字,和自己的名字
UpdateData(TRUE);
CString MyName = MainDialog->m_UserName;
// 2. 组合结构体
SEND_INFO SendInfo = { TYPE::CRTGRP, GetSafeHwnd() };
memcpy(SendInfo.CrtGrpInfo.Creator, MyName.GetBuffer(), MyName.GetLength() * 2);
memcpy(SendInfo.CrtGrpInfo.GrpName, m_AddEdit.GetBuffer(), m_AddEdit.GetLength() * 2);
// 3. 发送消息到服务器
::SendMessage(MainDialog->GetSafeHwnd(), UM_SEND_MSG, (WPARAM)& SendInfo, sizeof(SendInfo));
}
所需结构体
// 5. 建群消息
typedef struct _CRTGRP_INFO
{
WCHAR Creator[32];
WCHAR GrpName[32];
} CRTGRP_INFO, * PCRTGRP_INFO;
服务器接收处理并返回
# 创建群组的消息
def on_crtgrp(self, client, message):
# 解包获取发送来的数据
hwnd, creator, grpname = struct.unpack("i64s64s", message[:132])
# 获取群主和群名
creator = creator.decode("UTF16").strip("\x00")
grpname = grpname.decode("UTF16").strip("\x00")
# 查看当前的群是否已经存在
if self.mysql.select("SELECT * FROM group_table WHERE name='%s';" % grpname):
client.send(struct.pack("iii40s", Type.CRTGRP.value, hwnd, 0, "群组已存在".encode("UTF16")))
else:
# 如果不存在,向数据库中添加一组数据
self.mysql.exec("INSERT INTO group_table(name,user) VALUE('%s','%s')" % (grpname, creator))
# 直接将群主添加到群内
self.mysql.exec("INSERT INTO grpuser_table VALUE('%s', '%s');" % (grpname, creator))
# 将新建结果进行返回,返回额群名,方便进行添加
client.send(struct.pack("iii40s", Type.CRTGRP.value, hwnd, 1, grpname.encode("UTF16")))
客户端主窗口接收到并转发
// 响应建群
case TYPE::CRTGRP:
{
// 对于注册是否成功的消息,wParam 没有用,lParam 指向 RECV_STATE
::SendMessage(RecvInfo->hWnd, UM_RECV_CRTGRP, NULL, (LPARAM)& RecvInfo->RecvState);
break;
}
// 建群
afx_msg LRESULT CUserDialog::OnUmRecvCrtgrp(WPARAM wParam, LPARAM lParam)
{
// 将 lParam 转换成对应的的结构
PRECV_STATE RecvState = (PRECV_STATE)lParam;
// 判断是否添加成功
if (RecvState->IsSuccess)
{
// 如果成功执行直接添加到列表
m_TreeCtrl.InsertItem(&RecvState->MsgInfo[0], m_GrpNode);
return 0;
}
// 不成功执行这里
MessageBox(RecvState->MsgInfo);
return 0;
}
添加群组
按下添加按钮
// 添加群组
void CUserDialog::OnBnClickedAddgrp()
{
// 1. 获取群的名字,和自己的名字
UpdateData(TRUE);
CString MyName = MainDialog->m_UserName;
// 2. 组合结构体
SEND_INFO SendInfo = { TYPE::ADDGRP, GetSafeHwnd() };
memcpy(SendInfo.AddGrpInfo.User, MyName.GetBuffer(), MyName.GetLength() * 2);
memcpy(SendInfo.AddGrpInfo.Group, m_AddEdit.GetBuffer(), m_AddEdit.GetLength() * 2);
// 3. 发送消息到服务器
::SendMessage(MainDialog->GetSafeHwnd(), UM_SEND_MSG, (WPARAM)& SendInfo, sizeof(SendInfo));
}
所需结构体
// 6. 添加群组的消息
typedef struct _ADDGRP_INFO
{
WCHAR User[32];
WCHAR Group[32];
} ADDGRP_INFO, * PADDGRP_INFO;
服务器
# 发送添加群组的消息
def on_addgrp(self, client, message):
# 解包获取发送来的数据
hwnd, user, grpname = struct.unpack("i64s64s", message[:132])
# 获取目标用户和群组的名字
user = user.decode("UTF16").strip("\x00")
grpname = grpname.decode("UTF16").strip("\x00")
# 是否有这样一个群
if not self.mysql.select("SELECT * FROM group_table WHERE name='%s';" % grpname):
client.send(struct.pack("iii40s", Type.ADDGRP.value, hwnd, 0, "群组不存在".encode("UTF16")))
# 是否已经在群内了
elif self.mysql.select("SELECT * FROM grpuser_table WHERE grpname='%s' AND user='%s';" % (grpname, user)):
client.send(struct.pack("iii40s", Type.ADDGRP.value, hwnd, 0, "不能重复添加群组".encode("UTF16")))
# 添加成功的情况
else:
# 向数据库中添加一组信息 (群名,用户名)
self.mysql.exec("INSERT INTO grpuser_table VALUE('%s', '%s');" % (grpname, user))
# 在返回的消息处填写添加的好友的名称
client.send(struct.pack("iii40s", Type.ADDGRP.value, hwnd, 1, grpname.encode("UTF16")))
# 发送群聊消息
客户端
// 响应加群
case TYPE::ADDGRP:
{
// 对于注册是否成功的消息,wParam 没有用,lParam 指向 RECV_STATE
::SendMessage(RecvInfo->hWnd, UM_RECV_ADDGRP, NULL, (LPARAM)& RecvInfo->RecvState);
break;
}
// 加群
afx_msg LRESULT CUserDialog::OnUmRecvAddgrp(WPARAM wParam, LPARAM lParam)
{
// 将 lParam 转换成对应的的结构
PRECV_STATE RecvState = (PRECV_STATE)lParam;
// 判断是否添加成功
if (RecvState->IsSuccess)
{
// 如果成功执行直接添加到列表
m_TreeCtrl.InsertItem(&RecvState->MsgInfo[1], m_GrpNode);
return 0;
}
// 不成功执行这里
MessageBox(RecvState->MsgInfo);
return 0;
}
更新群组列表
初始化的时候发送请求
// 发消息给服务器更新好友列表
SEND_INFO SendInfo1 = { TYPE::UPDATEGRP, GetSafeHwnd() };
memcpy(SendInfo1.UpdateGrpInfo.Name, MainDialog->m_UserName.GetBuffer(),
MainDialog->m_UserName.GetLength() * 2);
// 通过主窗口向服务器发送消息
::SendMessage(MainDialog->GetSafeHwnd(), UM_SEND_MSG, (WPARAM)& SendInfo1, sizeof(SendInfo));
相关的结构体
// 7. 更新群组列表
typedef struct _UPDATEGRP_INFO
{
WCHAR Name[32];
} UPDATEGRP_INFO, * PUPDATEGRP_INFO;
服务器接收到处理之后发回来
# 发送群聊消息
def on_updategrp(self, client, message):
# 解包获取发送来的数据
hwnd, user = struct.unpack("i64s", message[:68])
# 获取目标用户名
user = user.decode("UTF16").strip("\x00")
# 查询目标用户的所有群组名称
friends = self.mysql.select("SELECT grpname FROM grpuser_table WHERE user='%s';" % user)
# 通过一个循环,将每一个群族名发送到客户端
for name in friends: # (("1"),("2"),("3"))
client.send(struct.pack("ii64s", Type.UPDATEGRP.value, hwnd, name[0].encode("UTF16")))
time.sleep(0.1)
客户端接受到消息之后处理
主窗口响应,转发
// 响应加群
case TYPE::UPDATEGRP:
{
// 对于注册是否成功的消息,wParam 没有用,lParam 指向 RECV_STATE
::SendMessage(RecvInfo->hWnd, UM_RECV_UPDATEGRP, NULL, (LPARAM)& RecvInfo->UpdateGrpInfo);
break;
}
转发到的地方
// 更新群组
afx_msg LRESULT CUserDialog::OnUmRecvUpdategrp(WPARAM wParam, LPARAM lParam)
{
// 转换成对应的结构体
PUPDATEGRP_INFO GrpInfo = (PUPDATEGRP_INFO)lParam;
// 【添加到树控件的好友节点中,收到的消息前两个字节会是 ff fe】
m_TreeCtrl.InsertItem(&GrpInfo->Name[1], m_GrpNode);
return 0;
}
群聊
双击树控件的时候跳出群聊框 参考好友
点击发送发送信息
void CGrpDialog::OnBnClickedSendmsg()
{
// 1. 获取编辑框(聊天记录 + 输入框)的内容
UpdateData(TRUE);
// 2. 将用户的输入拼接到聊天框的结尾
SYSTEMTIME SystemTime = { 0 };
GetSystemTime(&SystemTime);
CString TimeString;
TimeString.Format(L"%d:%d:%d %d:%d:%d", SystemTime.wYear,
SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour,
SystemTime.wMinute, SystemTime.wSecond);
m_ShowEdit += L"你 说(" + TimeString + L"):\r\n "
+ m_InputEdit + L"\r\n\r\n";
// 3. 将输入的数据进行组合,句柄是无效的
CString MyName = MainDialog->m_UserName;
SEND_INFO SendInfo = { TYPE::GRPMSG, NULL };
memcpy(SendInfo.GrpMsg.From, MyName.GetBuffer(), MyName.GetLength() * 2);
memcpy(SendInfo.GrpMsg.To, m_TargetName.GetBuffer(), m_TargetName.GetLength() * 2);
memcpy(SendInfo.GrpMsg.Msg, m_InputEdit.GetBuffer(), m_InputEdit.GetLength() * 2);
// 4. 通过主窗口发送到服务器
::SendMessage(MainDialog->GetSafeHwnd(), UM_SEND_MSG, (WPARAM)& SendInfo, sizeof(SEND_INFO));
// 5. 将组合的数据显示到输出框
m_InputEdit = "";
UpdateData(FALSE);
}
所需结构体
// 8. 群组消息
using GRPMSG_INFO = FRDMSG_INFO;
using PGRPMSG_INFO = PFRDMSG_INFO;
服务器接收到信息处理并发送回来
def on_grpmsg(self, client, message):
# 解包获取发送来的数据
hwnd, fromname, to, msg = struct.unpack("i64s64s200s", message[:332])
# 获取群组的名字
fromname = fromname.decode("UTF16").strip("\x00")
to = to.decode("UTF16").strip("\x00")
msg = to.msg("UTF16").strip("\x00")
# 查看当前群组的所有用户
users = self.mysql.select("SELECT user FROM grpuser_table WHERE grpname='%s'" % to)
# 遍历查到的所有用户,
for user in users:
# 判断是否在线,并且排除自己
if user[0] in self.dict_client and self.dict_client[user[0]] != client:
self.dict_client[user[0]].send(b"\x08\x00\x00\x00" + message)
客户端
case TYPE::GRPMSG:
{
// 1. 获取群组的名字,To 保存的是发送给具体的群
CString Name = RecvInfo->FrdMsg.To;
// 2. 判断有没有窗口标题为这个名字的窗口
if (WindowsMap.find(Name) == WindowsMap.end())
{
// 3. 如果没有这个窗口就进行创建
CGrpDialog* dialog = new CGrpDialog(Name);
dialog->Create(IDD_DIALOG3, this);
// 3.2.2 设置群聊天窗口的窗口名为群名
dialog->SetWindowText(Name);
dialog->ShowWindow(SW_SHOWNORMAL);
// 3.2.3 将新创建的窗口添加到字典中
WindowsMap[Name] = dialog;
}
// 4. 发送给对应的窗口
::SendMessage(WindowsMap[Name]->GetSafeHwnd(), UM_RECV_GRPMSG, NULL, (LPARAM)& RecvInfo->FrdMsg);
break;
}
afx_msg LRESULT CGrpDialog::OnUmRecvGrpmsg(WPARAM wParam, LPARAM lParam)
{
// 0. 转换成对应的结构体
PGRPMSG_INFO Msg = (PGRPMSG_INFO)lParam;
// 1. 获取编辑框(聊天记录)的内容
UpdateData(TRUE);
// 2. 将用户的输入拼接到聊天框的结尾
SYSTEMTIME SystemTime = { 0 };
GetSystemTime(&SystemTime);
CString TimeString;
TimeString.Format(L"%d:%d:%d %d:%d:%d", SystemTime.wYear,
SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour,
SystemTime.wMinute, SystemTime.wSecond);
m_ShowEdit += CString(Msg->From) + L" 说(" + TimeString + L"):\r\n "
+ Msg->Msg + L"\r\n\r\n";
// 3. 将组合的数据显示到输出框
UpdateData(FALSE);
return 0;
聊天室(C++客户端+Pyhton服务器)3.群功能添加的更多相关文章
- 聊天室(C++客户端+Pyhton服务器)_1.框架搭设
聊天室 一.客户端发送 用MFC可视化做个客户端登录界面. 先点击注册账号按钮,注册账号的时候就需要连接到服务器, 服务器需要查数据库,并做出相应的回应. 所以开始写C++客户端套接口类用来连接到服务 ...
- 利用html 5 websocket做个山寨版web聊天室(手写C#服务器)
在之前的博客中提到过看到html5 的websocket后很感兴趣,终于可以摆脱长轮询(websocket之前的实现方式可以看看Developer Works上的一篇文章,有简单提到,同时也说了web ...
- 聊天室(C++客户端+Pyhton服务器)2.基本功能添加
根据之前的框架添加新的功能 登录 点击相关按钮 // 登录按钮的响应void CMainDialog::OnBnClickedLogin(){ // 1. 获取用户输入的数据 UpdateData(T ...
- Qt实现网络聊天室(客户端,服务端)
1. 效果演示 客户端 服务器 连接成功之后 2. 预备知识 如果不知道网络编程的可以去看我的上一篇文章C++网络编程 在Qt中,实现网络编程的方式比用C++或C实现要方便简单许多,因为Qt已经替我们 ...
- h2engine游戏服务器设计之聊天室示例
游戏服务器设计之聊天室示例 简介 h2engine引擎建群以后,有热心网友向我反馈,想尝试h2engine但是没有服务器开发经验觉得无从入手,希望我能提供一个简单明了的示例.由于前一段时间工作实在忙碌 ...
- Java 网络编程 -- 基于TCP 实现聊天室 群聊 私聊
分析: 聊天室需要多个客户端和一个服务端. 服务端负责转发消息. 客户端可以发送消息.接收消息. 消息分类: 群聊消息:发送除自己外所有人 私聊消息:只发送@的人 系统消息:根据情况分只发送个人和其他 ...
- Netty学习笔记(六) 简单的聊天室功能之WebSocket客户端开发实例
在之前的Netty相关学习笔记中,学习了如何去实现聊天室的服务段,这里我们来实现聊天室的客户端,聊天室的客户端使用的是Html5和WebSocket实现,下面我们继续学习. 创建客户端 接着第五个笔记 ...
- Node.js下基于Express + Socket.io 搭建一个基本的在线聊天室
一.聊天室简单介绍 采用nodeJS设计,基于express框架,使用WebSocket编程之 socket.io机制.聊天室增加了 注册登录模块 ,并将用户个人信息和聊天记录存入数据库. 数据库采用 ...
- C 基于UDP实现一个简易的聊天室
引言 本文是围绕Linux udp api 构建一个简易的多人聊天室.重点看思路,帮助我们加深 对udp开发中一些api了解.相对而言udp socket开发相比tcp socket开发注意的细节要少 ...
随机推荐
- 【hdu 2222】Keywords Search
[题目链接] 点击打开链接 [算法] 此题是AC自动机模板题 AC自动机是很神奇的算法,简单点来说,就是在一棵字典树上进行KMP,它的应用范围很广,非常实用 这篇博客写得很好,推荐阅读 : http: ...
- ol 与ul 的区别
1 <!DOCTYPE html> <html> <body> <ul> <li>咖啡</li> <li>牛奶< ...
- lightoj 1025【区间DP】
题意: 给出一个word,求有多少种方法你从这个word清除一些字符而达到一个回文串. 思路: 区间问题,还是区间DP: 我判断小的区间有多少,然后往外扩大一点. dp[i,j]就代表从i到j的方案数 ...
- <TLE>奇偶剪枝hdoj1010
(奇偶剪枝)转自百度百科,讲的非常棒: http://baike.baidu.com/link?url=3g5bW7LszRVOVvFDFp6cL0ZZnAaOLUdpaNjc2leHoxkKU9Eh ...
- TFS 用户设置read权限后仍然无法查看代码的问题
TFS 2013 在visual studio , team explorer , source control explorer 中点击 文件夹 右键菜单 Security 打开一个winform( ...
- python __builtins__ str类 (65)
65.'str', 字节转换成字符串.第一个传入参数是要转换的字节,第二个参数是按什么编码转换成字符串 class str(object) | str(object='') -> str | s ...
- 黑客攻防技术宝典web实战篇:攻击应用程序逻辑习题
猫宁!!! 参考链接:http://www.ituring.com.cn/book/885 随书答案. 1. 何为强制浏览?可以通过它确定哪些漏洞? 强制浏览包括避开浏览器导航对应用程序功能访问顺序实 ...
- 怎么让普通用户达到root用户也可以拥有权限修改文件(CentOS系统)
为什么会提出这个问题呢? 答:因为啊,比如我们在大数据集群搭建的时候,经常会需要配置环境变量,如/etc/profile.那么,问题来了,每次必须得都切换到root用户才能,但是呢,如何可以在普通用户 ...
- SQL 列拼接使用
一个产品收藏表 Collection , 把该产品被收藏的人拼接在一列中如下: SQL SERVER SELECT ProjectID, UserIDs = ','+(STUFF((SELECT ', ...
- asp.net MVC中实现调取web api
public ActionResult Index(string city) { if (string.IsNullOrEmpty(city)) { city = "上海"; } ...