博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
聊天室(C++客户端+Pyhton服务器)2.基本功能添加
阅读量:4648 次
发布时间:2019-06-09

本文共 7359 字,大约阅读时间需要 24 分钟。

根据之前的框架添加新的功能

登录

点击相关按钮

// 登录按钮的响应 void CMainDialog::OnBnClickedLogin() {
// 1. 获取用户输入的数据 UpdateData(TRUE); // 2. 判断输入的数据是否为空 if (m_UserName.IsEmpty() || m_PassWord.IsEmpty()) { MessageBox(L"请输入用户名和密码"); return; } // 3. 填充需要发送的数据内容 SEND_INFO SendInfo = { TYPE::LOGIN, GetSafeHwnd() }; memcpy(SendInfo.LoginInfo.UserName, m_UserName.GetBuffer(), m_UserName.GetLength() * 2); memcpy(SendInfo.LoginInfo.PassWord, m_PassWord.GetBuffer(), m_PassWord.GetLength() * 2); // 4. 将数据通过自定义消息发送到服务器 SendMessage(UM_SEND_MSG, (WPARAM)& SendInfo, sizeof(SEND_INFO)); }

发送的结构体

// 1. 登录使用的的结构体 using LOGIN_INFO = _REGISTER_INFO; using PLOGIN_INFO = _REGISTER_INFO*;

 

python接收到后处理的方法

# 实例方式:用于处理登录消息     def on_login(self, client, message): # 解包获取发送来的数据 hwnd, username, password = struct.unpack("i64s64s", message[:132]) # 将用户名和密码进行解码 username = username.decode("UTF16").strip("\x00") password = password.decode("UTF16").strip("\x00") # 判断用户和密码是否存在于数据库中 if self.mysql.select("SELECT * FROM user_table WHERE user='%s' AND pswd=MD5('%s');" %(username, password)): # 如果用户名和密码匹配,返回结果 => 类型 + 句柄 + 是否成功 + 服务器返回的信息 client.send(struct.pack("iii40s", Type.LOGIN.value, hwnd, 1, "登录成功".encode("UTF16"))) # 将登录成功的用户添加到【在线用户】字典中 print(username, "登录了聊天室") self.dict_client[username] = client else: # 失败的信息 client.send(struct.pack("iii40s", Type.LOGIN.value, hwnd, 0, "用户名或密码不匹配".encode("UTF16")))

客户端接接受到服务端发来的消息做的反应

主窗口响应,转发

// 响应登录     case TYPE::LOGIN: { // 对于注册是否成功的消息,wParam 没有用,lParam 指向 RECV_STATE ::SendMessage(RecvInfo->hWnd, UM_RECV_LOGIN, NULL, (LPARAM)& RecvInfo->RecvState); break; }

转发到的地方响应

// 是否登录成功 afx_msg LRESULT CMainDialog::OnUmRecvLogin(WPARAM wParam, LPARAM lParam) { // 将 lParam 转换成对应的的结构 PRECV_STATE RecvState = (PRECV_STATE)lParam; // 判断是否登录成功 if (RecvState->IsSuccess) { // 弹出用户话框(好友、群组) CUserDialog* dialog = new CUserDialog; dialog->Create(IDD_USERDIALOG, this); // [ 对话框必须是非模态的,否则会导致消息的阻塞 ] // [ 对话框必须是保存在堆空间中,否则离开作用域会销毁 ] return dialog->ShowWindow(SW_SHOWNORMAL); } // 不成功执行这里 MessageBox(RecvState->MsgInfo); }

 

 

登录之后进到一个新的界面

获取父窗口句柄

//构造函数内设置主窗口 CUserDialog::CUserDialog(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_USERDIALOG, pParent) , m_AddEdit(_T("")) { // 保存父窗口 MainDialog = (CMainDialog*)AfxGetMainWnd(); }

 

设置标题

初始化树控件

// 初始化对话框(获取用户和群组) BOOL CUserDialog::OnInitDialog() {
CDialogEx::OnInitDialog(); // 隐藏父窗口 MainDialog->ShowWindow(SW_HIDE); SetWindowText(MainDialog->m_UserName + L"主窗口"); // 添加好友分组和群组的节点 m_FrdNode = m_TreeCtrl.InsertItem(L"好友列表"); m_GrpNode = m_TreeCtrl.InsertItem(L"群组列表"); return TRUE; }

 

 

 

C++客户端添加好友功能

客户端向服务器发送要添加的消息

获取要添加的名字

打包发送给服务器

/ 添加好友按钮的响应 void CUserDialog::OnBnClickedAddfrd() {
// 1. 获取自己的名字和目标名称 UpdateData(TRUE); CString MyName = MainDialog->m_UserName; // 2. 自己不能添加自己为好友 if (MyName == m_AddEdit) { MessageBox(L"无法添加自己为好友!"); return; } // 3. 组合消息 SEND_INFO SendInfo = { TYPE::ADDFRD, GetSafeHwnd() }; memcpy(SendInfo.AddFrdInfo.User1, MyName.GetBuffer(), MyName.GetLength() * 2); memcpy(SendInfo.AddFrdInfo.User2, m_AddEdit.GetBuffer(), m_AddEdit.GetLength() * 2); // 4. 通过主窗口发送消息 ::SendMessage(MainDialog->GetSafeHwnd(), UM_SEND_MSG, (WPARAM)& SendInfo, sizeof(SendInfo)); }

 

打包前得先弄信息结构体

// 2. 添加好友的消息 typedef struct _ADDFRD_INFO {
WCHAR User1[32]; WCHAR User2[32]; } ADDFRD_INFO, * PADDFRD_INFO;

 

 

服务端接收到消息之后的处理

添加类型

添加方法

定义方法

添加新的表单friend_table

user1

user2

发送回客户端

 

# 添加好友的消息     def on_addfrd(self, client, message): # 解包获取发送来的数据 hwnd, user1, user2 = struct.unpack("i64s64s", message[:132]) # 获取双方的用户名 user1 = user1.decode("UTF16").strip("\x00") user2 = user2.decode("UTF16").strip("\x00") # 是否有这样一个用户 if not self.mysql.select("SELECT * FROM user_table WHERE user='%s';" % user2): client.send(struct.pack("iii40s", Type.ADDFRD.value, hwnd, 0, "用户不存在".encode("UTF16"))) # 是否已经是我的好友 elif self.mysql.select("SELECT * FROM friend_table WHERE user1='%s' AND user2='%s';" % (user1, user2)): client.send(struct.pack("iii40s", Type.ADDFRD.value, hwnd, 0, "不能重复添加好友".encode("UTF16"))) # 添加成功的情况 else: # 向数据库中添加一组信息 (我,好友) self.mysql.exec("INSERT INTO friend_table VALUE('%s', '%s');" % (user1, user2)) # 在返回的消息处填写添加的好友的名称 client.send(struct.pack("iii40s", Type.ADDFRD.value, hwnd, 1, user2.encode("UTF16")))
客户端接收到服务器的反馈的反应

要用非模态的对话框,否则信息会堵塞

 

主窗口响应,转发

// 响应加好友     case TYPE::ADDFRD: { // 对于注册是否成功的消息,wParam 没有用,lParam 指向 RECV_STATE ::SendMessage(RecvInfo->hWnd, UM_RECV_ADDFRD, NULL, (LPARAM)& RecvInfo->RecvState); break; }

转发到的地方

// 查看是否成功 afx_msg LRESULT CUserDialog::OnUmRecvAddfrd(WPARAM wParam, LPARAM lParam) { // 将 lParam 转换成对应的的结构 PRECV_STATE RecvState = (PRECV_STATE)lParam; // 判断是否添加成功 if (RecvState->IsSuccess) { // 如果成功执行直接添加到列表 m_TreeCtrl.InsertItem(RecvState->MsgInfo, m_FrdNode); return 0; } // 不成功执行这里 MessageBox(RecvState->MsgInfo); return 0; }

 

更新好友列表

打开好友的时候会自动更新好友列表

初始化的时候发送请求

// 发消息给服务器更新好友列表     SEND_INFO SendInfo = { TYPE::UPDATEFRD, GetSafeHwnd() }; memcpy(SendInfo.UpdateFrdInfo.User, MainDialog->m_UserName.GetBuffer(), MainDialog->m_UserName.GetLength() * 2); // 通过主窗口向服务器发送消息 ::SendMessage(MainDialog->GetSafeHwnd(), UM_SEND_MSG, (WPARAM)& SendInfo, sizeof(SendInfo));

相关的结构体

// 3. 更新好友列表 typedef struct _UPDATEFRD_INFO {
WCHAR User[32]; } UPDATEFRD_INFO, * PUPDATEFRD_INFO;

 

服务器接收到处理之后发回来

# 更新好友的消息     def on_updatefrd(self, client, message): # 解包获取发送来的数据 hwnd, user = struct.unpack("i64s", message[:68]) # 获取目标用户名 user = user.decode("UTF16").strip("\x00") # 查询目标用户的所有好友名称 friends = self.mysql.select("SELECT user2 FROM friend_table WHERE user1='%s';" % user) # 通过一个循环,将每进一个用户名发送到客户端 for name in friends: # (("1"),("2"),("3")) client.send(struct.pack("ii64s", Type.UPDATEFRD.value, hwnd, name[0].encode("UTF16"))) time.sleep(0.1)

 

客户端接受到消息之后处理

主窗口响应,转发

// 响应更新好友     case TYPE::UPDATEFRD: { // 对于注册是否成功的消息,wParam 没有用,lParam 指向 RECV_STATE ::SendMessage(RecvInfo->hWnd, UM_RECV_UPDATEFRD, NULL, (LPARAM)& RecvInfo->RecvState); break; }

转发到的地方

// 响应更新好友的消息 afx_msg LRESULT CUserDialog::OnUmRecvUpdatefrd(WPARAM wParam, LPARAM lParam) { // 转换成对应的结构体 PUPDATEFRD_INFO UserInfo = (PUPDATEFRD_INFO)lParam; // 【添加到树控件的好友节点中,收到的消息前两个字节会是 ff fe】 m_TreeCtrl.InsertItem(&UserInfo->User[1], m_FrdNode); return 0; }

 

 

 

好友私聊

私聊窗口的界面

客户端的话,双击树控件的好友的时候要能弹出聊天窗口,

所以需要响应树控件按钮

 

字典#include<map>

using namespace std:

判断是不是好友窗口,群窗口同理

窗口可以双击打开,

// 响应窗口聊天 void CUserDialog::OnDblclkTree1(NMHDR* pNMHDR, LRESULT* pResult) { // 1. 获取当前点击的这一个子节点的内容 HTREEITEM CurrentNode = m_TreeCtrl.GetSelectedItem(); CString Name = m_TreeCtrl.GetItemText(CurrentNode); // 2. 判断节点是不是[好友列表]或者[群组列表] if (Name.Compare(L"好友列表") && Name.Compare(L"群组列表")) { // 3.1 判断窗口是否已经存在 if (MainDialog->WindowsMap.find(Name) != MainDialog->WindowsMap.end()) { // 存在则显示,确保一个窗口只会被打开一次 MainDialog->WindowsMap[Name]->ShowWindow(SW_SHOWNORMAL); } // 3.2 判断是不是好友聊天窗口 else if (m_TreeCtrl.GetParentItem(CurrentNode) == m_FrdNode) { // 3.2.1 创建用户聊天窗口 CFrdDialog* dialog = new CFrdDialog(Name); dialog->Create(IDD_DIALOG2, this); // 3.2.2 设置用户聊天窗口的窗口名为点击的文字 dialog->SetWindowText(Name); dialog->ShowWindow(SW_SHOWNORMAL); // 3.2.3 将新创建的窗口添加到字典中 MainDialog->WindowsMap[Name] = dialog; } // 3.3 判断是不是群组聊天窗口 else if (m_TreeCtrl.GetParentItem(CurrentNode) == m_GrpNode) { // 3.3.1 创建群组聊天窗口 CGrpDialog* dialog = new CGrpDialog(Name); dialog->Create(IDD_DIALOG3, this); // 3.3.2 设置群组聊天窗口的窗口名为点击的文字 dialog->SetWindowText(Name); dialog->ShowWindow(SW_SHOWNORMAL); // 3.3.3 将新创建的窗口添加到字典中 MainDialog->

转载于:https://www.cnblogs.com/ltyandy/p/11031511.html

你可能感兴趣的文章
实验5
查看>>
git 下载 安装
查看>>
录制终端信息并回放
查看>>
JS中window.event事件使用详解
查看>>
ES6深入学习记录(一)class方法相关
查看>>
《BI项目笔记》用Excel2013连接和浏览OLAP多维数据集
查看>>
C语言对mysql数据库的操作
查看>>
SQL Server 数据库备份
查看>>
INNO SETUP 获得命令行参数
查看>>
Charles抓取https请求
查看>>
LAMP环境搭建
查看>>
C语言的变量的内存分配
查看>>
clientcontainerThrift Types
查看>>
链接全局变量再说BSS段的清理
查看>>
hdu 1728 逃离迷宫
查看>>
HTML5与CSS3权威指南之CSS3学习记录
查看>>
docker安装部署
查看>>
AVL树、splay树(伸展树)和红黑树比较
查看>>
多媒体音量条显示异常跳动
查看>>
运算符及题目(2017.1.8)
查看>>