C++打造局域网聊天室第十二课: 客户端和服务端的切换

news/2024/12/23 22:41:49 标签: c++, 开发语言, mfc

文章目录

  • 前言
  • 一、补充说明
  • 二、客户端和服务端身份状态的切换
  • 三、点击关闭窗口按钮
  • 总结


前言

C++打造局域网聊天室第十二课: 客户端和服务端的切换


一、补充说明

在C++打造局域网聊天室第十一课: 程序关闭及线程的结束中描述的服务端线程的关闭和结束是存在bug的,这里进行补充说明。
按照上述链接的程序,在关闭服务端时,会出现如下bug:
在这里插入图片描述
在这里插入图片描述
即在第一次点击服务端停止按钮后,客户端不会出现服务端断开提示,在第二次点击服务端停止按钮后,客户端才出现提示。经过博主Debug发现造成这种现象的原因是:在点击服务端停止按钮后,由于服务端对应的bShutDown为1,Server.cpp中的程序会跳出死循环,但是之前对于Server.cpp中的程序只实现了关闭监听线程,而与客户端通信的线程没有调用closesocket()关闭。所以WaitForMultipleObjects()会超时,调用TerminateThread()进行强制与客户端连接线程的结束,由于第一次点击服务端停止按钮后WaitForMultipleObjects()超时,客户端的SOCKET_Select(m_ClientItem.m_Socket, 100, TRUE)函数不会返回1,所以客户端不会出现服务端断开提示。而在第二次点击服务端停止按钮时,服务端的监听线程和与客户端的通信线程已经全都关闭,WaitForMultipleObjects()不会超时,所以客户端会正常提示。解决办法为在Server.cpp的如图位置加入框中代码:
在这里插入图片描述
此时,在第一次点击服务端停止按钮后,不光对服务端监听线程进行了关闭,也对与客户端通信的线程进行了关闭,WaitForMultipleObjects()不会超时,客户端会正常提示:
在这里插入图片描述

二、客户端和服务端身份状态的切换

如果本程序为客户端,点击服务端选项后,要提醒用户,并停止客户端。添加后,点击服务器选项和客户端选项的MFC消息映射机制函数变为:

void CchartroomDlg::OnBnClickedRadio2()//点击服务器选项的MFC消息映射机制
{
	// TODO: 在此添加控件通知处理程序代码
	INT iRet = -1;
	// 添加客户端切换服务端程序
	if (m_bIsServer == 0) // 如果当前程序为服务端
	{
		iRet = MessageBox(_T("您正在聊天中,要退出吗?"), 0, MB_OKCANCEL);
		if (iRet == IDOK) // 如果用户真想关闭
		{
			StopClient(); // 停止服务端
		}
		else
		{
			CheckRadioButton(IDC_RADIO1, IDC_RADIO2, IDC_RADIO1); // 置为客户端
		}
	}
	if (iRet == IDOK || m_bIsServer == -1)
	{
		EnableWindow(IDC_BUTTON2, 0);// 利用自己定义的函数禁用客户器端的停止按钮
		EnableWindow(IDC_IPADDRESS1, 0);// 利用自己定义的函数禁用服务器IP
		EnableWindow(IDC_EDIT6, 0);// 利用自己定义的函数禁用服务器端口
		EnableWindow(IDC_BUTTON1, 0);// 利用自己定义的函数禁用连接服务器
		EnableWindow(IDC_BUTTON2, 0);// 利用自己定义的函数禁用客户端的停止按钮
		EnableWindow(IDC_EDIT7, 1);// 利用自己定义的函数允许本地监听端口
		EnableWindow(IDC_BUTTON3, 1);// 利用自己定义的函数允许开启服务器
		EnableWindow(IDC_BUTTON4, 1);// 利用自己定义的函数允许服务器端停止按钮
	}


}

void CchartroomDlg::OnBnClickedRadio1()//点击客户端选项的MFC消息映射机制
{
	// TODO: 在此添加控件通知处理程序代码
	INT iRet = -1;
	// 添加服务端切换客户端程序
	if (m_bIsServer == 1) // 如果当前程序为服务端
	{
		iRet = MessageBox(_T("您是聊天室的服务端,如果您退出,所有客户端都会掉线"), 0, MB_OKCANCEL);
		if (iRet == IDOK) // 如果用户真想关闭
		{
			StopServer(); // 停止服务端
		}
		else
		{
			CheckRadioButton(IDC_RADIO1, IDC_RADIO2, IDC_RADIO2); // 置为服务端
		}
	}
	if (iRet == IDOK || m_bIsServer == -1)
	{
		EnableWindow(IDC_BUTTON2, 1);// 利用自己定义的函数允许客户器端的停止按钮
		EnableWindow(IDC_IPADDRESS1, 1);// 利用自己定义的函数允许服务器IP
		EnableWindow(IDC_EDIT6, 1);// 利用自己定义的函数允许服务器端口
		EnableWindow(IDC_BUTTON1, 1);// 利用自己定义的函数允许连接服务器
		EnableWindow(IDC_BUTTON2, 1);// 利用自己定义的函数允许客户端的停止按钮
		EnableWindow(IDC_EDIT7, 0);// 利用自己定义的函数禁用本地监听端口
		EnableWindow(IDC_BUTTON3, 0);// 利用自己定义的函数禁用开启服务器
		EnableWindow(IDC_BUTTON4, 0);// 利用自己定义的函数禁用服务器端停止按钮
	}
}

三、点击关闭窗口按钮

在这里插入图片描述
点击关闭后,不光要关闭窗口,还要终止服务端和客户端对应的线程

void CchartroomDlg::OnBnClickedButton6() // 点击关闭窗口按钮的MFC消息映射机制
{
	// TODO: 在此添加控件通知处理程序代码
	if (m_bIsServer == 1) // 如果为服务端
	{
		StopServer();
	}
	else if (m_bIsServer == 0) // 如果为客户端
	{
		StopClient();
	}
	OnCancel(); // 关闭窗口
}

总结

C++打造局域网聊天室第十二课: 客户端和服务端的切换


http://www.niftyadmin.cn/n/5797084.html

相关文章

Python调用open ai接口

要使用 Python 调用 OpenAI 的接口,您需要完成以下几个步骤: 1. **注册并获取 API 密钥** 2. **安装 OpenAI 的 Python 库** 3. **编写 Python 代码以调用 API** 以下是详细的步骤说明: --- ### 1. 注册并获取 API 密钥 首先&#xff0c…

AtCoder Beginner Contest 385(A~F)题解

A - Equally 思路&#xff1a;由题可知最多只能分成三组&#xff0c;我们只需要判断是否三个数都相等&#xff0c;或者两个数相加等于另外一个数即可 #include<bits/stdc.h> using namespace std; #define int long long int n; string s; int a,b,c; signed main() {ci…

MySQL 主从复制与高可用

在现代分布式系统中&#xff0c;数据库的高可用性和可靠性至关重要。MySQL 提供了主从复制&#xff08;Master-Slave Replication&#xff09;机制来实现数据的冗余和容错&#xff0c;保证在主数据库发生故障时能够继续提供服务。而在此基础上&#xff0c;通过进一步的高可用架…

严格推导质点曲线运动的运动学方程

前言 相当一部分物理学书籍在推导质点曲线运动的运动学方程时&#xff0c;采用的都是先建立位移的微元 Δ r ⃗ \Delta \vec{r} Δr &#xff0c;然后几何近似求极限的方法。这种方法虽然能得到正确的结论&#xff0c;但数学上的严格性略有欠缺&#xff0c;且过程繁琐。考虑到…

tomcat的安装以及配置(基于linuxOS)

目录 安装jdk环境 yum安装 验证JDK环境 安装tomcat应用 yum安装 ​编辑 使用yum工具进行安装 配置tomcat应用 关闭防火墙和selinux 查看端口开启情况 ​编辑 访问tomcat服务 安装扩展包 重启服务 查看服务 源码安装 进入tomcat官网进行下载 查找自己要用的to…

html <a>设置发送邮件链接、打电话链接 <a href=“mailto:></a> <a href=“tel:></a>

1.代码 <ul><li>电话&#xff1a;<a href"tel:18888888888">188-8888-8888</a></li><li>邮箱&#xff1a;<a href"mailto:10000qq.com">10000qq.com</a></li><li>邮箱&#xff1a;<a hre…

sql注入之union注入

Sql注入之union注入攻击 今天讲讲sql注入攻击流程 事先声明&#xff0c;本文仅仅作为学习使用&#xff0c;因个人原因导致的后果&#xff0c;皆与本人无关&#xff0c;后果由个人承担。 本次演示靶机为封神台里的题目&#xff0c;具体连接如下 https://hack.zkaq.cn/battle…

<代码随想录> 算法训练营-2024.12.20

322. 零钱兑换 class Solution:def coinChange(self, coins: List[int], amount: int) -> int:# dp[i][j]表示 提供到coins[i]的硬币&#xff0c;总金额为j的最少硬币个数 硬币个数无限&#xff0c;完全背包# 有两种取值&#xff0c;一种是取dp[i-1][j] 另一种是如果j比当前…