基于MFC实现的网络教室

1.项目名称:Windows 下的网络教室 

2.项目目的:实现同一局域网下服务器和客户端的通信。

3.项目描述:基于 MFC 实现了页面的布局。设置服务器实现教师与学生的通讯,用客户端模拟教 师和学生两种角色,并实现注册和登录的功能。教师端按下开始抢答后,学生端可以抢答。学生端可以进行举手、提交作业的操作,并且学生端的界面可以显示答题信息和在线好友列表。

4.项目要点:

1.使用中介者模式 观察者模式,中介者处理多个类之间的耦合性,观察者模式在接收到具体的网络消息,能够自动更新自己。

2.整个项目分为服务器和客户端,客户端又分为教师端、学生端。

3.我们要自定义数据包来识别不同的数据,这让我联想到了消息队列。

4.不同计算机结构体对齐方式不同? 序列化、反序列化。

5.因为学生的人数很多,数据类型又多,在这里我们使用数据库存储。

6.UDP广播获得好友列表,上传下载作业使用TCP。

7.怎么判断第一个学生抢到题,采用标识的方式,加锁。

8.如果是学生人数较多、但是不经常交作业,采用选择模型(Select)比较好。如果是学生人数比较多,经常要长传作业要使用完成端口模型。

5.代码部分

5.1服务器端

5.11数据库部分

MyDao.h

#pragma once
#ifndef __INCLUDE_MY_DAO_H__
#define __INCLUDE_MY_DAO_H__
#include <windows.h>
#include <list>
#include <stdio.h>
#include <tchar.h>
using namespace std;
#pragma warning(disable:4018 4996 4172)
#import "C:\\Program Files\\Common Files\\System\\ado\\msado15.dll" no_namespace rename("EOF","ADOEOF") rename("BOF","ADOBOF")
#define DATEBASE_TYPE_ACCESS	0
#define DATEBASE_TYPE_SQL2000   1
#define DATEBASE_TYPE_SQL2005   2
#define DATEBASE_TYPE_OTHER		3
#define DEF_MAX_STR_LEN			(100)
class CMyDao
{
public:
	CMyDao();
	~CMyDao();
	BOOL InitCom();        //初始化com组件
	void releaseCom();     //释放com组件

public:
	//初始化数据库
	BOOL OpenDateBase(TCHAR* strDateBaseName,int nDataType,TCHAR* strUser,TCHAR* strPassWord,TCHAR* strIP);

	//关闭数据库
	void CloseDataBase();

	//添加数据
	BOOL AddData(TCHAR* strTableName,list<TCHAR*>& strCloumValue,int nCloumNum);
	//字符串转换为指定类型
	BOOL StringToDataType(TCHAR* strValue,int nDataType, VARIANT *pVar);

	//获取数据
	BOOL GetData(TCHAR* strSql,list<TCHAR*>& strQueryCloum,int nCloumNum,list<TCHAR*>& strDataValue);

	//数据转字符串
	TCHAR* DataToStringType(VARIANT Var);

	//修改数据
	BOOL EditData(TCHAR* strSQL, int nColumnNum, list<TCHAR*>& pStrFieldName, list<TCHAR*> &saValue);

	//删除数据
	BOOL DeleteData(TCHAR* strSQL);

private:
	//获取指定位置的值
	TCHAR* GetPos(list<TCHAR*>& str, int iPos)
	{
		if (str.size() <= iPos)
		{
			return NULL;
		}
		list<TCHAR*>::iterator it = str.begin();
		int iCount = 0;
		while (it != str.end())
		{
			if (iCount++ == iPos)
			{
				break;
			}
			it++;
		}

		return *it;
	}

private:
	_ConnectionPtr m_pConnection;  //连接数据库的指针对象
	_RecordsetPtr  m_pRecordset;   //操作记录集的指针对象
	_CommandPtr    m_pCommandmsg;  //SQL命令的指针对象

	BOOL m_binitComFlag;
	TCHAR m_strErrorMsg[DEF_MAX_STR_LEN];         //错误信息
	TCHAR m_strConnect[DEF_MAX_STR_LEN];          //连接串
};

#endif //__INCLUDE_MY_DAO_H__

MyDao.cpp

                     #include "stdafx.h"
#include "MyDao.h"                                                                                                                                                                                                              
CMyDao::CMyDao()
{
	m_binitComFlag = FALSE;
	InitCom();
}
CMyDao::~CMyDao()
{
	releaseCom();
}
BOOL CMyDao::InitCom()
{
	#if _WIN32_WINNT > 0x500
		//保留字(必须为null) ,加载方式 COINIT_MULTITHREADED多线程的方式加载
		// 以多线程方式打开com通道
		::CoInitializeEx(NULL, COINIT_MULTITHREADED);
	#else
		::CoInitialize(NULL);
	#endif
		m_binitComFlag = TRUE;
	return TRUE;
}
void CMyDao::releaseCom()
{
	if (m_binitComFlag)
	{
		::CoUninitialize();
	}
}
////////////////////////////////////////////////////////////////////
//初始化数据库
BOOL CMyDao::OpenDateBase(TCHAR* strDateBaseName,int nDataType,TCHAR* strUser,TCHAR* strPassWord,TCHAR* strIP)
{
	//"colin",DATEBASE_TYPE_SQL2005,"sa","sa","127.0.0.1,2433"
	if (nDataType == DATEBASE_TYPE_ACCESS)
	{
		//CFileFind filefind;
		//BOOL bFind = filefind.FindFile(strDateBaseName);

		//if (!bFind)
		//{
		//	m_strErrorMsg = _T("找不到数据库");
		//	return FALSE;
		//}
		//else
		//{
		//	m_strConnect.Format(_T("provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s"),strDateBaseName);
		//}
	}
	else if (nDataType == DATEBASE_TYPE_SQL2000)
	{
		_stprintf(m_strConnect, _T("Driver={SQL Server};Server=%s;Uid=%s;Pwd=%s;Database=%s"), strIP,strUser,strPassWord,strDateBaseName);
		//m_strConnect.Format(_T("Driver={SQL Server};Server=%s;Uid=%s;Pwd=%s;Database=%s"),strIP,strUser,strPassWord,strDateBaseName);
	}
	else if (nDataType == DATEBASE_TYPE_SQL2005)
	{
		_stprintf(m_strConnect, _T("Driver={SQL Native Client};Server=%s;Uid=%s;Pwd=%s;Database=%s"), strIP,strUser,strPassWord,strDateBaseName);
		//m_strConnect.Format(_T("Driver={SQL Native Client};Server=%s;Uid=%s;Pwd=%s;Database=%s"),strIP,strUser,strPassWord,strDateBaseName);
	}
	else
	{
		_tcscpy(m_strErrorMsg, _T("没有合适的连库串"));
		return FALSE;
	}

	//实例化指针对象
	HRESULT hRes;
	//把CString转换成com组件里的字符串变量
	_bstr_t bstrConnection(m_strConnect);
	_bstr_t bstrUser(strUser);
	_bstr_t bstrPassword(strPassWord);

	try
	{
		//创建连接对象 序列码
		hRes = m_pConnection.CreateInstance(__uuidof(Connection));
		if (!SUCCEEDED(hRes))
		{
			_tcscpy(m_strErrorMsg, _T("实例化连接指针对象失败"));
			//m_strErrorMsg = _T("实例化连接指针对象失败");
			return FALSE;
		}

		//连接数据库(连库串,用户名,密码,打开方式)
		//字符串要用的是com组件的字符串 adModeShareDenyNone多用户共同可以访问一个数据库
		hRes = m_pConnection->Open(bstrConnection,bstrUser,bstrPassword,adModeShareDenyNone);
		if (!SUCCEEDED(hRes))
		{
			_tcscpy(m_strErrorMsg, _T("打开数据库失败"));
			//m_strErrorMsg = _T("打开数据库失败");
			return FALSE;
		}

		//实例化数据集指针对象
		hRes = m_pRecordset.CreateInstance(__uuidof(Recordset));
		if (!SUCCEEDED(hRes))
		{
			_tcscpy(m_strErrorMsg, _T("实例化数据集指针对象失败"));
			//m_strErrorMsg = _T("实例化数据集指针对象失败");
			return FALSE;
		}
		//实例化命令集指针对象
		hRes = m_pCommandmsg.CreateInstance(__uuidof(Command));
		if (!SUCCEEDED(hRes))
		{
			_tcscpy(m_strErrorMsg, _T("实例化命令集指针对象失败"));
			//m_strErrorMsg = _T("实例化命令集指针对象失败");
			return FALSE;
		}

	}catch(_com_error *e)
	{
		//AfxMessageBox(e->Description());
		//m_strErrorMsg.Format(_T("%s"),e->Description());
		_stprintf(m_strErrorMsg, _T("%s"), e->Description());
		return FALSE;
	}

	return TRUE;
}

//关闭数据库
void CMyDao::CloseDataBase()
{
	//TODO:
	m_pConnection->Close();
	//m_pConnection.DestroyInstance();
}

//添加数据
BOOL CMyDao::AddData(TCHAR* strTableName,list<TCHAR*>& strCloumValue,int nCloumNum)
{
	TCHAR strQuery[100];
	_stprintf(strQuery, _T("select * from [%s]"),strTableName);
	//strQuery.Format(_T("select * from [%s]"),strTableName);

	//自带的字符串类型
	_bstr_t bstrQuery(strQuery);
	_bstr_t bstrCource(m_strConnect);

	HRESULT hres;
	Fields *pFiles = NULL;
	//ado把所有的数据类型都写在VARIANT这里面
	VARIANT varIndex;
	varIndex.vt = VT_I4; //R代表float CY==钱数  VT_带表的都是comADO代表的数据类型

	Field  *pFile = NULL;
	DataTypeEnum dataType;

	VARIANT varValue;
	try
	{
		//打开表
		hres = m_pRecordset->Open(bstrQuery,bstrCource,adOpenDynamic,adLockBatchOptimistic,adCmdText);
		if (!SUCCEEDED(hres))
		{
			//m_strErrorMsg = _T("打开表失败");
			_stprintf(m_strErrorMsg, _T("打开表失败"));
			return FALSE;
		}
		else
		{
			//计算添加记录的行数
			int nRosNum = (int)(strCloumValue.size()/nCloumNum);
			if(nRosNum <= 0 )
			{
				//m_strErrorMsg = _T("参数个数错误");
				//AfxMessageBox(_T("输入参数错误,请重新输入"));
				_stprintf(m_strErrorMsg, _T("参数个数错误"));
				return FALSE;
			}
			//添加记录 循环行
			for (int i=0; i<nRosNum; i++)
			{
				//记录集告诉要添加记录
				m_pRecordset->AddNew();
				//要把记录一列一列的写进去
				for (int ncloum=0;ncloum<nCloumNum;ncloum++)
				{
					//传入的都是字符串 我要先得到列的数据类型 然后在做相应的转换 再把数据添加到数据库里
					//在数据库里列都是以集合形式存在的,所以先要得到所有的列,在从中得到每一个列
					//Fields *pFiles 是个双指针
					//1.得到所有的列
					m_pRecordset->get_Fields(&pFiles);

				//2.得到具体的列
				//ADO的COM对数据库编程 除了定义了字符串其他的没有具体定义 ado把所有的数据类型都写在VARIANT这里面
					varIndex.intVal = ncloum;
					pFiles->get_Item(varIndex,&pFile);

					//3.得到列(字段)对应的数据类型
					pFile->get_Type(&dataType);

					//4.转换 CString--》对应的类型 0 1 2 3 4 5   3
					//TODO:
					//if (StringToDataType(strCloumValue.GetAt(ncloum+i*nCloumNum),dataType,&varValue))
					if (StringToDataType(GetPos(strCloumValue, ncloum+i*nCloumNum),dataType,&varValue))
					{
						//5.添加记录
						pFile->put_Value(varValue);
						if (varValue.vt == (VT_UI1|VT_ARRAY))
						{
							SafeArrayDestroy(varValue.parray);
						}
					}
					
				}
				//更新数据
				m_pRecordset->UpdateBatch(adAffectCurrent);

			}
			//关闭记录集 如果不关闭就会被一直占用,就打不开了
			//if (pStrReturnID)
			//{
			//	m_pRecordset->MoveLast();
			//	m_pRecordset->get_Fields(&pFiles);

			//	varIndex.intVal = 0;
			//	pFiles->get_Item(varIndex,&pFile);
			//	VARIANT varKey;
			//	pFile->get_Value(&varKey);

			//	pStrReturnID->Format(_T("%d"),varKey.intVal);
			//}

			m_pRecordset->Close();
		}
	}catch(_com_error *e)
	{
		//AfxMessageBox(e->Description());
		//m_strErrorMsg.Format(_T("%s"),e->Description());
		_stprintf(m_strErrorMsg, _T("%s"),e->Description());
		return FALSE;
	}

	return TRUE;
}

//字符串转换为指定类型
BOOL CMyDao::StringToDataType(TCHAR* strValue,int nDataType, VARIANT *pVar)
{
	switch(nDataType)
	{
	case adInteger: //整形
		pVar->vt = VT_I2;
		pVar->intVal = _ttoi(strValue);
		break;
	case adBoolean: //BOOL类型
		pVar->vt = VT_BOOL;
		pVar->bVal = _ttoi(strValue);
		break;
	case adSingle:   //单精度
		pVar->vt = VT_R4;
		pVar->fltVal = (float)_tstof(strValue);
		break;
	case adDouble:  //双精度
		pVar->vt = VT_R8;
		pVar->dblVal = _tstof(strValue);
		break;
	case adBSTR:   //字符串
	case adChar:
	case adVarChar:
	case adVarWChar:	
	case adWChar:
	case adLongVarWChar:
	case adLongVarChar:
		pVar->vt = VT_BSTR;
		pVar->bstrVal = (bstr_t)strValue;
		break;
	default:
		pVar->vt = VT_EMPTY;
		break;
	}
	return TRUE;
}

//获取数据
BOOL CMyDao::GetData(TCHAR* strSql,list<TCHAR*>& strQueryCloum,int nCloumNum,list<TCHAR*>& strDataValue)
{
	HRESULT het;
	//_bstr_t    字符串    		_variant_t 多种数据类型集合 vt类型   ..value值								//com
	_bstr_t bstrSql = strSql;				//执行sql
	_bstr_t bstrConnect = m_strConnect;		//连库串
	_bstr_t bstrQueryCloum;					//列名

	Fields *fields;
	FieldPtr fieldPtr;

	TCHAR strValue[100];
	_variant_t varBLOB;

	try
	{
		het = m_pRecordset->Open(bstrSql,bstrConnect,adOpenDynamic,adLockOptimistic,adCmdText);
		if (!SUCCEEDED(het))
		{
			//AfxMessageBox(_T("打开表失败"));
			//m_strErrorMsg = _T("查询表失败");
			_stprintf(m_strErrorMsg, _T("查询表失败"));
			return FALSE;
		}
		//循环结果
		  list<TCHAR*>::iterator it;
		   //行
		while(!m_pRecordset->ADOEOF)
		{
			//	列
			it = strQueryCloum.begin();
			for(int i=0;i<nCloumNum,it != strQueryCloum.end();i++,it++)
			{
				bstrQueryCloum = *it;
				//		获得所有列
				fields = m_pRecordset->GetFields();
					  //获得指定列
				fieldPtr = fields->GetItem(bstrQueryCloum);
					 //获得列对应的值
				varBLOB = fieldPtr->GetValue();
				
				//long nSize =fieldPtr->ActualSize;
				
				
				//注意图片名称必须为图片流的前一个字段
				//strValue = DataToCStringType(varBLOB,nSize,strValue);
				//strValue = DataToCStringType(varBLOB);
				_stprintf(strValue, _T("%s"), DataToStringType(varBLOB));
				TCHAR* pCopy = new TCHAR[_tcslen(strValue)+1];
				_tcscpy(pCopy, strValue);
				strDataValue.insert(strDataValue.begin(), pCopy);
				 
				//varBLOB.Detach();
			}
			m_pRecordset->MoveNext();
		}

		m_pRecordset->Close();
	}
	catch(_com_error *e)
	{
		//m_strErrorMsg = e->ErrorMessage();
		//AfxMessageBox(e->ErrorMessage());
		_stprintf(m_strErrorMsg, _T("%s"), e->ErrorMessage());
	}

	return TRUE;
}

//数据转字符串
TCHAR* CMyDao::DataToStringType(VARIANT Var)
{
	TCHAR strValue[100];
	switch(Var.vt)
	{
	case VT_BOOL:
		//strValue.Format(_T("%d"), Var.boolVal);
		_stprintf(strValue, _T("%d"), Var.boolVal);
		break;
	case VT_I4:
		//strValue.Format(_T("%d"), Var.intVal);
		_stprintf(strValue, _T("%d"), Var.intVal);
		break;
	case VT_R8:
	case VT_DECIMAL:
		//strValue.Format(_T("%0.2f"), Var.dblVal);
		_stprintf(strValue, _T("%0.2f"), Var.dblVal);
		break;
	case VT_BSTR:
		_stprintf(strValue, _T("%s"), Var.bstrVal);
		//strValue= Var.bstrVal;
		break;
	default:
		_stprintf(strValue, _T(""));
		break;
	}

	return strValue;
}
//修改数据
BOOL CMyDao::EditData(TCHAR* strSQL, int nColumnNum, list<TCHAR*>& pStrFieldName, list<TCHAR*> &saValue)
{
	int nIndex = 0;		//列的索引
	int nCount = 0;		//修改的总数
	int nTotal = (int)saValue.size();  //一共修改的个数

	HRESULT hRet;
	_variant_t varFieldName;
	_variant_t varValue;

	_bstr_t bstrQuery = strSQL;
	_bstr_t bstrConnent = m_strConnect;
	try
	{
		hRet = m_pRecordset->Open(bstrQuery, bstrConnent, adOpenDynamic, adLockOptimistic, adCmdText);
		if(!SUCCEEDED(hRet))
		{
			_tcscpy(m_strErrorMsg, _T("打开表失败"));
			//m_strErrorMsg = _T("打开表失败!");
			return FALSE;
		}
		if (m_pRecordset->ADOEOF)
		{
			_tcscpy(m_strErrorMsg, _T("没有选择修改的行"));
			//m_strErrorMsg = _T("没有选择修改的行");
			m_pRecordset->Close();
			return FALSE;
		}
		Fields *pFiles = NULL;
		//ado把所有的数据类型都写在VARIANT这里面
		VARIANT varIndex;
		varIndex.vt = VT_I4; //R代表float CY==钱数  VT_带表的都是comADO代表的数据类型

		Field  *pFile = NULL;
		list<TCHAR*>::iterator it = pStrFieldName.begin();
		list<TCHAR*>::iterator itValue = saValue.begin();
		while(!m_pRecordset->ADOEOF)
		{
			////修改哪一列  s#  sname    1 'ss'  2 'ss2'   stringarr  4    2
			//varFieldName.SetString((bstr_t)pStrFieldName[nIndex]);
			varFieldName.SetString((bstr_t)(*it));

			//varValue.SetString((bstr_t)saValue.GetAt(nCount));
			varValue.SetString((bstr_t)(*itValue));

			m_pRecordset->Update(varFieldName,varValue);
			nIndex++;
			it++;
			nCount++;
			itValue++;
			if(nIndex>=nColumnNum)
			{
				nIndex = 0;
				it = pStrFieldName.begin();
				m_pRecordset->MoveNext();
			}

			if (nColumnNum == 1)
			{
				if(nCount == nTotal)
				{
					break;
				}
			}
			else
			{
				if(nCount > nTotal)
				{
					break;
				}
			}
		}
		m_pRecordset->Close();
	}
	catch(_com_error *e)
	{
		//m_strErrorMsg = e->ErrorMessage();
		//AfxMessageBox(e->Description());
		_stprintf(m_strErrorMsg, _T("%s"), e->Description());
		return FALSE;
	}

	return TRUE;
}

//删除数据
BOOL CMyDao::DeleteData(TCHAR* strSQL)
{
	HRESULT hRet;

	_bstr_t bstrQuery = strSQL;
	_bstr_t bstrConnent = m_strConnect;

	try
	{
		hRet = m_pRecordset->Open(bstrQuery, bstrConnent, adOpenDynamic, adLockOptimistic, adCmdText);
		if(!SUCCEEDED(hRet))
		{
			_tcscpy(m_strErrorMsg, _T("打开表失败"));
			//m_strErrorMsg = _T("打开表失败!");
			return FALSE;
		}
		while(!m_pRecordset->ADOEOF)
		{
			m_pRecordset->Delete(adAffectCurrent);
			m_pRecordset->MoveNext();
		}

		m_pRecordset->Close();
	}
	catch(_com_error *e)
	{
		//AfxMessageBox(e->Description());
		_stprintf(m_strErrorMsg, _T("%s"), e->Description());
		return FALSE;
	}
	
	return TRUE;
}

5.12IKernel部分

IKernel.h

#pragma once 
#include "INet.h"
#include <list>
using namespace std;
class IKernel 
{
public:
    IKernel();
    virtual ~IKernel();
public:
    virtual bool Open() = 0;
    virtual void Close() = 0;
    virtual bool RecvData(long lRevip,char *szContent) = 0;
public:
    void Attact(INet* pNet);
    void Detach(INet* pNet);
    void Notify(StateType ntype);
private:
    list<INet*> m_lstNet;
};

IKernel.cpp

#include "stdafx.h"
#include "IKernel.h"
 IKernel::IKernel()
 {
 }
IKernel::~IKernel()
{
    m_lstNet.clear();
}
void IKernel::Attact(INet* pNet)
{
    if(pNet == NULL)return;

    m_lstNet.push_back(pNet);
}
void IKernel::Detach(INet* pNet)
{
    list<INet*>::iterator ite = m_lstNet.begin();
    while(ite != m_lstNet.end())
    {
        if(*ite == pNet)
        {
            ite = m_lstNet.erase(ite);
            break;
        }
        ite++;
    }

}

void IKernel::Notify(StateType ntype)
{
    list<INet*>::iterator ite = m_lstNet.begin();
    while(ite != m_lstNet.end())
    {
        (*ite)->Update(ntype);
        ite++;
    }
}
Kernel.h
#pragma once
#include "IKernel.h"
#include "UDPNet.h"
#include "MyDao.h"
class Kernel :public IKernel
{
public:
    Kernel();
    virtual ~Kernel();
public:
    virtual bool Open();
    virtual void Close();
    virtual bool RecvData(long lRevip,char *szContent);
public:
    void SetTeacherState(bool   bTeacherState)
    {
        m_bTeacherState = bTeacherState;
    }
    bool GetTeacherState()
    {
        return m_bTeacherState;
    }
private:
    INet *m_UDPNet;
    CMyDao m_ado;
    bool   m_bbusy;
    bool   m_bTeacherState;
    long   m_lteacherIp;
};

Kernel.cpp

#include "stdafx.h"
#include "Kernel.h"

 Kernel::Kernel()
 {
     m_UDPNet = new UDPNet(this);
     Attact(m_UDPNet);

     m_bbusy = false;
     m_bTeacherState = false;
 }

Kernel::~Kernel()
{
    if(m_UDPNet)
    {
        delete m_UDPNet;
        m_UDPNet = NULL;
    }
}

bool  Kernel::Open()
{
    //连接数据库
    m_ado.OpenDateBase(L"ElectronicResponder",DATEBASE_TYPE_SQL2005,L"sa",L"sa",L".");
    //通知启动服务器
    Notify(SY_BEGIN);
    return true;
}

void  Kernel::Close()
{
    //通知结束服务器
    Notify(SY_END);
    
}

bool Kernel::RecvData(long lRevip,char *szContent)
{
     if(lRevip == INet::GetValidIp())
     {
           return true;
     }
    int *ptype = (int*)szContent;
    switch(*ptype)
    {
    case PT_REGISTER_RQ: //注册信息包 --去数据库中比较数据,如果不存在此人,则加入数据库 ,如果存在,返回失败
        {
            STRU_USERINFO *psu = ( STRU_USERINFO *)szContent;
            list<TCHAR*> lstValue;
            TCHAR szname[_DEFAULTNUM]= {0};
            TCHAR szPassword[_DEFAULTNUM]= {0};
            TCHAR szRole[_DEFAULTNUM]= {0};
            STRU_USERINFO_RS su;
#ifdef _UNICODE
     MultiByteToWideChar(CP_ACP,0,psu->m_szUserName,-1,szname,_DEFAULTNUM);
     MultiByteToWideChar(CP_ACP,0,psu->m_szPassWord,-1,szPassword,_DEFAULTNUM);
     MultiByteToWideChar(CP_ACP,0,psu->m_szRole,-1,szRole,_DEFAULTNUM);
#else
     strcpy_s(szname,_DEFAULTNUM,psu->m_szUserName); 
     strcpy_s(szPassword,_DEFAULTNUM,psu->m_szPassWord); 
     strcpy_s(szRole,_DEFAULTNUM,psu->m_szRole); 
#endif
            lstValue.push_back(_T(""));
           
            lstValue.push_back(szname);
            lstValue.push_back(szPassword);
            lstValue.push_back(szRole);

             
            if(m_ado.AddData(_T("UserInfo"),lstValue,4))
            {
                su.m_bflag = 1;
            }
            else
            {
                su.m_bflag = 0;
            }

            //已经注册成功
          
           
            m_UDPNet->SendData(lRevip,(char*)&su,sizeof(su));
            //m_ado.GetData();
        }
        break;
   case PT_LOGIN_RQ: //登录信息包--去数据库检验信息,给此人回复
       {
           STRU_USERINFO_RS su;
           su.m_ntype = PT_LOGIN_RS;
           
           STRU_USERINFO *psu = ( STRU_USERINFO *)szContent;
           TCHAR *sql = _T("select UserName,UserPassWord,userRole from USERINFO")  ;
           list<TCHAR*> lstcolumn;
           list<TCHAR*> lstValue;

            TCHAR szname[_DEFAULTNUM]= {0};
            TCHAR szPassword[_DEFAULTNUM]= {0};
            TCHAR szRole[_DEFAULTNUM]= {0};

#ifdef _UNICODE
     MultiByteToWideChar(CP_ACP,0,psu->m_szUserName,-1,szname,_DEFAULTNUM);
     MultiByteToWideChar(CP_ACP,0,psu->m_szPassWord,-1,szPassword,_DEFAULTNUM);
     MultiByteToWideChar(CP_ACP,0,psu->m_szRole,-1,szRole,_DEFAULTNUM);
#else
     strcpy_s(szname,_DEFAULTNUM,psu->m_szUserName); 
     strcpy_s(szPassword,_DEFAULTNUM,psu->m_szPassWord); 
     strcpy_s(szRole,_DEFAULTNUM,psu->m_szRole); 
#endif

           lstcolumn.push_back(_T("UserName"));
           lstcolumn.push_back(_T("UserPassWord"));
           lstcolumn.push_back(_T("userRole"));

           m_ado.GetData(sql,lstcolumn,lstcolumn.size(),lstValue);

           list<TCHAR*>::iterator itevalue = lstValue.begin();

		   while(lstValue.size() >0)
           {
               //如果用户不同,则找下一个用户名
			  
               if(0 == wcscmp( lstValue.back(),szname))
               {
				   lstValue.pop_back();
                    if(0 == wcscmp( lstValue.back(),szPassword))
                    {
                            lstValue.pop_back();
                          
                           if(0 == wcscmp( lstValue.back(),szRole))
                           {
                                 //如果是教师角色,则将教师状态置为在线状态
                               if(0 == wcscmp(L"teacher",szRole))
                               {
                                   SetTeacherState(true);
                                   m_lteacherIp = lRevip;
                               }
                               su.m_bflag = 1;
                               break;
                           }
                           else
                           {
                               break;
                           }
                    }
                    else
                    {
                        break;
                    }
               }



                 lstValue.pop_back();
                 lstValue.pop_back();
                 lstValue.pop_back();
           }
           //登录成功,或者失败通知

          m_UDPNet->SendData(lRevip,(char*)&su,sizeof(su));

       }
       break;
    case PT_ONLINE_RQ://上线通知包--将当前包发送给所有人
        {
          
             m_UDPNet->SendData(INADDR_BROADCAST,szContent,sizeof(STRU_BROADCASTINFO));
        }
        break;
    case PT_OFFLINE_NTF: //下线
        {
            STRU_BROADCASTINFO *psb = ( STRU_BROADCASTINFO *)szContent;
            //如果是教师下线了,则教师状态置为离线
            if(lRevip == m_lteacherIp)
            {
                SetTeacherState(false);
                m_lteacherIp = 0;
            }
           
            m_UDPNet->SendData(INADDR_BROADCAST,szContent,sizeof(STRU_BROADCASTINFO));
        }
        break;
    case  PT_QUICKANSWER: //抢答包--将包发给所有人
        {
            if(*ptype == PT_QUICKANSWER)
            {
                m_bbusy = false;
            }
           
            m_UDPNet->SendData(INADDR_BROADCAST,szContent,sizeof(STRU_QUICKANSWER));
        }
        break;
    case PT_DATA: //数据bao -- 将包发给所有人
        {
           
             m_UDPNet->SendData(INADDR_BROADCAST,szContent,sizeof(STRU_DATAINFO));
        }
        break;
    case PT_ONLINE_RS: //上线回复包 -- 将包发给指定的人
        {
            STRU_BROADCASTINFO *psb = ( STRU_BROADCASTINFO *)szContent;

            m_UDPNet->SendData(psb->m_lTargetIp,szContent,sizeof(STRU_BROADCASTINFO));
        }
        break;
    case PT_ANSWER_RACE://我要抢答(ip)---将信息发给服务器,服务器给所有人发送停止抢答包,(包含)个人信息(ip)
        //        将状态置为空闲状态,
        {
             if(!m_bbusy)
             {
                 m_bbusy = true; 
                 //发送数据包通知所有人who 抢答成功
                 STRU_DATAINFO sd;
                 in_addr inaddr;
                 inaddr.S_un.S_addr = lRevip;
                 
                 memcpy(sd.m_szContent,inet_ntoa(inaddr),sizeof(sd.m_szContent));
                 strcpy_s(sd.m_szContent,"抢答成功");
                   //发送停止抢答包给所有人
                 STRU_QUICKANSWER sq;
                 sq.m_bflag =0;
                 sq.m_lHostIp = lRevip;
                
            
                 m_UDPNet->SendData(INADDR_BROADCAST,(char*)&sq,sizeof(STRU_QUICKANSWER));
                  m_UDPNet->SendData(INADDR_BROADCAST,(char*)&sd,sizeof(STRU_DATAINFO));

             }
             
        
        }
        break;
    case PT_SUMMITWORK_RQ://提交作业请求,查看教师是否在线,在线发教师的ip,离线,发自己的IP
        {
            STRU_SUMMITWORK ss;
            ss.m_ntype = PT_SUMMITWORK_RS;
            
            if(GetTeacherState())
            {
                ss.m_lIp = m_lteacherIp;
            }
            else
            {
                ss.m_lIp = INet::GetValidIp();
            }

            m_UDPNet->SendData(lRevip,(char*)&ss,sizeof(STRU_SUMMITWORK));
        }
        break;
    }
    return true;
 }

5.13网络部分

INet.h

#pragma once 

#include "Packdef.h"
#include <winsock2.h>

#pragma comment(lib, "ws2_32.lib")
class INet
{
public:
    INet(){}
    virtual ~INet(){}
public:
    //获得本机Ip地址
    static long GetValidIp()
    {
      
        in_addr addr;
        char szname[20] = {0};
        if(!gethostname(szname,20))
        {
           struct hostent* phost =  gethostbyname(szname);
           if(phost->h_addr_list[0] != 0)
           {
               addr.s_addr = *(u_long *) phost->h_addr_list[0];
                return addr.s_addr;
           }
        }

        return 0;
    }

    virtual bool InitNetWork() = 0;
    virtual bool UnInitNetWork() = 0;
    virtual bool SendData(unsigned long lSendIp,char* szbuf,int nlen) = 0;

    virtual void Update(StateType ntype) = 0;
};

UDPNet.h

#include "INet.h"
#include "IKernel.h"
class UDPNet :public INet
{
public:
    UDPNet(IKernel *pKernel);
    virtual ~UDPNet();
public:
   
    virtual bool InitNetWork();
    virtual bool UnInitNetWork();
    virtual bool SendData(unsigned long lSendIp,char* szbuf,int nlen);

    virtual void Update(StateType ntype);

    static unsigned _stdcall ThreadProc( void * lpvoid);
    void RecvData();
    bool  SelectSocket(SelectType ntype,SOCKET sock);
private:
    SOCKET m_sockListen;
    HANDLE m_hThread;
    bool   m_bFlagQuit;
    IKernel *m_pKernel;

};

UDPNet.cpp

#include "stdafx.h"
#include "UDPNet.h"
#include <process.h>
UDPNet::UDPNet(IKernel *pKernel)
{
    m_sockListen = NULL;
    m_hThread = NULL;
    m_bFlagQuit = false;
    m_pKernel = pKernel;
}
UDPNet::~UDPNet()
{

}

bool UDPNet::InitNetWork()
{
    //1.选择店规模  -- 加载库

	 WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
    
      
        return false;
    }



    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
        UnInitNetWork();
        return false;
    }
 
	//2.创建店。店长 -- 创建套接字socket 
	m_sockListen = socket(AF_INET,SOCK_DGRAM  ,IPPROTO_UDP);
	if(INVALID_SOCKET  == m_sockListen)
	{
		UnInitNetWork();
        return false;
	}
	//3.绑定信息(店名,地址,电话)-绑定(ip,端口号)bind 
	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr =GetValidIp();
	addr.sin_port = htons(_DEFAULTPORT);
	if(SOCKET_ERROR == bind(m_sockListen,(const sockaddr*)&addr,sizeof(sockaddr_in)))
	{
		UnInitNetWork();
        return false;
	}

	//广播属性
	bool optval = true;
	setsockopt(m_sockListen,SOL_SOCKET,SO_BROADCAST,(const char*)&optval,sizeof(bool));

    //接收数据--I/O select 
    m_bFlagQuit = true;
    m_hThread = (HANDLE) _beginthreadex(NULL,0,&ThreadProc,this,0,NULL);

    return true;
}

unsigned _stdcall UDPNet::ThreadProc( void * lpvoid)
{
    UDPNet *pthis = (UDPNet *)lpvoid;
    pthis->RecvData();
   
    return 0;
}

 bool  UDPNet::SelectSocket(SelectType ntype,SOCKET sock)
 {
     TIMEVAL tv;
     tv.tv_sec = 0;
     tv.tv_usec = 100;
     //1.创建集合
     fd_set fdsets;
     //2.清空集合
     FD_ZERO(&fdsets);
     //3.将socket 放入集合内
     FD_SET(sock,&fdsets);
     //4.将集合交给SELECT 去管理
     if(ntype == ST_READ)
     {
         select(NULL,&fdsets,NULL,NULL,&tv);
     }
     else  if(ntype == ST_WRITE)
     {
          select(NULL,NULL,&fdsets,NULL,&tv);
     }

     //5.检验socket 是否发生网络事件
     if(!FD_ISSET(sock,&fdsets))
     {
         return false;
     }

     return true;
 }

void UDPNet::RecvData()
{
    char szbuf[_DEFAULTPACKEF] = {0};
    sockaddr_in addr;
    int nsize;
     while(m_bFlagQuit)
    {
         nsize = sizeof(sockaddr_in);
        //接收数据
        if(SelectSocket(ST_READ,m_sockListen))
        {
            int nres = recvfrom(m_sockListen,szbuf,_DEFAULTPACKEF,0,(sockaddr*)&addr,&nsize);
            if(nres > 0 )
            {
                //交给Kernel 处理
                m_pKernel->RecvData(addr.sin_addr.s_addr,szbuf);

            }
        }
      
    }
}

bool UDPNet::UnInitNetWork()
{
    WSACleanup();
    if(m_sockListen)
    {
        closesocket(m_sockListen);
        m_sockListen = NULL;
    }

    if(m_hThread)
    {
        m_bFlagQuit = false;
        if(WAIT_TIMEOUT ==  WaitForSingleObject(m_hThread,100))
        {
            TerminateThread(m_hThread,-1);
        }

        CloseHandle(m_hThread);
        m_hThread = NULL;
    }

    return true;
}

bool UDPNet::SendData(unsigned long lSendIp,char* szbuf,int nlen)
{

    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(_DEFAULTPORT);
    addr.sin_addr.S_un.S_addr = (ULONG)lSendIp;

    if(sendto(m_sockListen,szbuf,nlen,0,(const sockaddr*)&addr,sizeof(addr)) <= 0)
    {
        return false;
    }

    return true;
}

void UDPNet::Update(StateType ntype)
{
   
    switch (ntype)
    {
    case SY_BEGIN:
        InitNetWork();
        break;
    case SY_END:
        UnInitNetWork();
        break;
    default:
        break;
    }
}

5.13数据包部分

#ifndef _PACKDEF_H
#define _PACKDEF_H 

#define _DEFAULTPORT  1234

#define _DEFAULTPACKEF    1024
#define _DEFAULTSIZE      200

#define _DEFAULTNUM        20


//执行标识
enum  StateType{SY_BEGIN,SY_END};

//select 管理缓冲区的类型  
enum  SelectType{ST_WRITE,ST_READ};

//包类型
enum  PackType{PT_REGISTER_RQ,PT_REGISTER_RS,PT_LOGIN_RQ,PT_LOGIN_RS,
               PT_ONLINE_RQ, PT_ONLINE_RS,PT_OFFLINE_NTF,PT_QUICKANSWER,
               PT_DATA,PT_ANSWER_RACE,PT_SUMMITWORK_RQ,PT_SUMMITWORK_RS};
//协议包
//注册包。登录包
struct STRU_USERINFO
{
    STRU_USERINFO()
    {
        m_ntype = PT_REGISTER_RQ;
        ZeroMemory(m_szUserName,_DEFAULTNUM);
        ZeroMemory(m_szPassWord,_DEFAULTNUM);
        ZeroMemory(m_szRole,_DEFAULTNUM);
        ZeroMemory(m_szCheck,_DEFAULTNUM);
       
    }
    PackType  m_ntype; 
    char      m_szUserName[_DEFAULTNUM];
    char      m_szPassWord[_DEFAULTNUM];
    char      m_szRole[_DEFAULTNUM];
    char      m_szCheck[_DEFAULTNUM];
};

struct STRU_USERINFO_RS
{
    STRU_USERINFO_RS()
    {
        m_ntype = PT_REGISTER_RS;
        m_bflag = 0;
    }
   PackType  m_ntype; 
   bool      m_bflag;

};

//上线。xiaxian 
struct STRU_BROADCASTINFO
{
    STRU_BROADCASTINFO()
    {
        m_ntype = PT_ONLINE_RQ;
        m_lHostIp = 0;
        m_lTargetIp = 0;
    }
     PackType  m_ntype; 
     long      m_lHostIp;
     long      m_lTargetIp;

};

//快速抢答 -- 开始抢答,停止抢答
struct STRU_QUICKANSWER
{
    STRU_QUICKANSWER()
    {
        m_ntype = PT_QUICKANSWER;
        m_bflag = 1;
        m_lHostIp = 0;
    }
     PackType  m_ntype; 
     bool      m_bflag; 
     long      m_lHostIp;

};
//停止扩展包---这个是为了学生抢答完成,服务器告诉所有人停止抢答
struct STRU_QUICKANSWEREX
{
    STRU_QUICKANSWEREX()
    {
        m_ntype = PT_QUICKANSWER;
        m_bflag = 1;
        m_lip = 0;
    }
     PackType  m_ntype; 
     bool      m_bflag; 
     long      m_lip;

};

//数据包--发送
struct STRU_DATAINFO
{
  STRU_DATAINFO()
  {
      m_ntype = PT_DATA;
      ZeroMemory(m_szContent,_DEFAULTSIZE);
      m_lhostIp = 0;
  }
   PackType  m_ntype; 
   char      m_szContent[_DEFAULTSIZE];
   long      m_lhostIp;

};

//我要抢答 --个人信息,
struct STRU_ANSWER_RACE
{
    STRU_ANSWER_RACE()
    {
        m_ntype = PT_ANSWER_RACE;
   
        m_lHostIp = 0;
    }
    PackType  m_ntype; 
  
    long      m_lHostIp;
};

//提交作业
struct STRU_SUMMITWORK
{

   STRU_SUMMITWORK()
    {
        m_ntype = PT_SUMMITWORK_RQ;
        m_lIp = 0;
    }
    PackType  m_ntype; 
    long      m_lIp;
};

#endif

5.14线程池部分

MyQueue.h

#pragma once

class CLock
{
public:
	CLock()
	{ InitializeCriticalSection(&m_cs);}
	~CLock()
	{DeleteCriticalSection(&m_cs);}
	void Lock()
	{EnterCriticalSection(&m_cs);}
	void UnLock()
	{LeaveCriticalSection(&m_cs);}
private:
	CRITICAL_SECTION m_cs;
};

class CAutoLock
{
public:
	CAutoLock(CLock& autolock):m_autolock(autolock)
	{m_autolock.Lock();}
	~CAutoLock()
	{m_autolock.UnLock();}
private:
	CLock& m_autolock;
};

template<class T>
class MyQueue
{
public:
	MyQueue():m_lReadPos(0),m_lWritePos(0),m_lQueueLen(0)
	{}
	~MyQueue()
	{}
	bool InitQueue(int len)
	{
         if(len <=0)
		 {
			 return false;
		 }
	   m_lQueueLen = len;
       m_pQueue = new T*[len];

	   for(long i = 0;i < len;i++)
	   {
		   m_pQueue[i] = NULL;
	   }

	   return true;
	}
	bool push(T* node)
	{
		CAutoLock WriteLock(m_WriteLock);
		//如果当前位置不为空,直接返回
		if(m_pQueue[m_lWritePos] != NULL)
		{
			return false;
		}
		m_pQueue[m_lWritePos] = node;
		
		m_lWritePos = (m_lWritePos +1)%m_lQueueLen;
		return true;
	}
	bool  pop(T*& node)
	{
		CAutoLock ReadLock(m_ReadLock);
		if(m_pQueue[m_lReadPos] == NULL)
		{
			return false;
		}
		node = m_pQueue[m_lReadPos];
		m_pQueue[m_lReadPos] = NULL;
		m_lReadPos = (m_lReadPos +1)%m_lQueueLen;
		return true;

	}
	void UnInitQueue()
	{
		for(long i =0;i <m_lQueueLen;i++)
		{
			if(m_pQueue[i])
			{
				delete m_pQueue[i];
				m_pQueue[i] = NULL;
			}
		}
		delete m_pQueue;
		m_pQueue = NULL;
	}
private:
	T** m_pQueue;
	long m_lReadPos;
	long m_lWritePos;
	long m_lQueueLen;
	CLock m_ReadLock;
	CLock m_WriteLock;
};

MyThreadPool.h

#pragma once
#include <list>
#include <windows.h>
#include "MyQueue.h"
namespace MyThreadPool
{
	class Itask
	{
	public:
		Itask(){}
		virtual ~Itask(){}

	public:
		virtual void Runitask() = 0;

	};


	class ThreadPool
	{
	public:
		ThreadPool(void);
		~ThreadPool(void);
		//1.创建线程池
		bool CreateThreadPool(long lMinThreadNum,long lMaxThreadNum,long lItaskNum);
		//2.销毁线程池
		void DestroyThreadPool();
		//3.线程函数(执行任务)
		static unsigned long  _stdcall ThreadProc( void* lpParameter);
		//4.投递任务
		bool PushItask(Itask *);
	private:
		//std::queue<Itask *> m_qItask;
		std::list<HANDLE> m_lstThread;
		bool m_bflagQuit;
		HANDLE     m_hSemphore;
		long   m_lRunThreadNum;
		long   m_lCreateThreadNum;
		long   m_lMaxThreadNum;
		//CRITICAL_SECTION m_cs;
		MyQueue<Itask> m_qItask;
	};
}

ThreadPool.cpp

#include "stdafx.h"
#include "ThreadPool.h"


using namespace MyThreadPool;

ThreadPool::ThreadPool(void)
{
	m_bflagQuit = false;
	m_hSemphore = NULL;
	m_lRunThreadNum = 0;
	m_lCreateThreadNum =0;
	m_lMaxThreadNum = 0;
	//InitializeCriticalSection(&m_cs);
}


ThreadPool::~ThreadPool(void)
{
	DestroyThreadPool();
}
bool ThreadPool::CreateThreadPool(long lMinThreadNum,long lMaxThreadNum,long lItaskNum)
{
	//1.校验参数
	if(lMinThreadNum <=0 || lMaxThreadNum <=0 )
	{
		return false;
	}

	//2.创建线程
	//创建信号量
	if(!m_qItask.InitQueue(lItaskNum/5))
	{
		return false;
	}

	m_hSemphore = CreateSemaphore(NULL,0,lMaxThreadNum,NULL);
	m_bflagQuit = true;
	for(long i = 0;i < lMinThreadNum;i++ )
	{
		 HANDLE hThread = CreateThread(NULL,0,&ThreadProc,this,0,NULL);
		 if(hThread)
		 {
			 m_lstThread.push_back(hThread);
		 }
	}

	m_lCreateThreadNum = lMinThreadNum;
	m_lMaxThreadNum = lMaxThreadNum;
	return true;
}

bool ThreadPool::PushItask(Itask *pItask)
{
	if(!pItask)return false;
	//将任务加到队列中
	/*EnterCriticalSection(&m_cs);
	m_qItask.push(pItask);
	LeaveCriticalSection(&m_cs);
	*/
	while(!m_qItask.push(pItask))
	{
		Sleep(1);
	}
	//如果有空闲服务员
	if(m_lRunThreadNum < m_lCreateThreadNum)
	{
		//释放信号量
		ReleaseSemaphore(m_hSemphore,1,NULL);
	}
	else if( m_lCreateThreadNum < m_lMaxThreadNum )
	{
		//如果没有闲的服务员,但是有空地,雇佣新的服务员
		 HANDLE hThread = CreateThread(NULL,0,&ThreadProc,this,0,NULL);
		 if(hThread)
		 {
			 m_lstThread.push_back(hThread);
		 }
		 m_lCreateThreadNum++;
		 //释放信号量
		ReleaseSemaphore(m_hSemphore,1,NULL);
	}
	else 
	{
		//店满了,智能等待
	}

	return true;
}

unsigned long  _stdcall ThreadPool::ThreadProc( void* lpParameter)
{
	ThreadPool  *pthis = (ThreadPool*)lpParameter;

	Itask *pitask = NULL;
	while(pthis->m_bflagQuit)
	{
		//等任务--信号量
		WaitForSingleObject(pthis->m_hSemphore,INFINITE);

		//将空闲状态转换为工作状态 
		//pthis->m_lRunThreadNum++;
		InterlockedIncrement(&pthis->m_lRunThreadNum);

		//取任务
		while(pthis->m_bflagQuit)
		{
		
			if(pthis->m_qItask.pop(pitask))
			{
				pitask->Runitask();
			    delete pitask;
			}
			else
			{
				break;
			}
			
		}
		
	
		//将工作的服务员转换为空闲状态
		//pthis->m_lRunThreadNum--;
		InterlockedDecrement(&pthis->m_lRunThreadNum);
	}
	return 0;
}


void ThreadPool::DestroyThreadPool()
{
	m_bflagQuit = false;
	ReleaseSemaphore(m_hSemphore,m_lCreateThreadNum,NULL);
	Sleep(100);
	std::list<HANDLE>::iterator iteThread;
	for(iteThread = m_lstThread.begin();iteThread != m_lstThread.end();iteThread++)
	{
		
		if(WAIT_TIMEOUT == WaitForSingleObject((*iteThread),100))
		{
			TerminateThread(*iteThread,-1);
		}
		if(*iteThread)
		{
			CloseHandle(*iteThread);
			*iteThread =  NULL;
		}
	}

	if(m_hSemphore)
	{
		CloseHandle(m_hSemphore);
		m_hSemphore = NULL;
	}
	//释放空间
	/*Itask *pitask = NULL;
	while(!m_qItask.empty())
	{
		pitask = m_qItask.front();
		m_qItask.pop();

		delete pitask;
	}

	DeleteCriticalSection(&m_cs);*/
}

5.2客户端

5.2.1Ikenel部分

IKernel.h

#pragma once 
#include "INet.h"
#include <list>
using namespace std;
class IKernel 
{
public:
    IKernel();
    virtual ~IKernel();
public:
    virtual bool Open(HWND hwnd) = 0;
    virtual void Close() = 0;
    virtual bool RecvData(long lRevip,char *szContent) = 0;
    virtual bool SendData(long lSendip,char *szContent,int nsize) = 0;
public:
    void Attact(INet* pNet);
    void Detach(INet* pNet);
    void Notify(StateType ntype);
private:
   
    list<INet*> m_lstNet;
};

IKernel.cpp

#include "stdafx.h"
#include "IKernel.h"
 IKernel::IKernel()
 {
 }
IKernel::~IKernel()
{
    m_lstNet.clear();
}
void IKernel::Attact(INet* pNet)
{
    if(pNet == NULL)return;

    m_lstNet.push_back(pNet);
}
void IKernel::Detach(INet* pNet)
{
    list<INet*>::iterator ite = m_lstNet.begin();
    while(ite != m_lstNet.end())
    {
        if(*ite == pNet)
        {
            ite = m_lstNet.erase(ite);
            break;
        }
        ite++;
    }

}
void IKernel::Notify(StateType ntype)
{
    list<INet*>::iterator ite = m_lstNet.begin();
    while(ite != m_lstNet.end())
    {
        (*ite)->Update(ntype);
        ite++;
    }
}

Kernel.h

#pragma once

#include "IKernel.h"
#include "UDPNet.h"
#include "tcpnet.h"
class Kernel :public IKernel
{
public:
    Kernel();
    virtual ~Kernel();
public:
    void SetHwnd(HWND hwnd)
    {
        m_hWnd = hwnd;
    }
    virtual bool Open(HWND hwnd);
    virtual void Close();
    virtual bool RecvData(long lRevip,char *szContent);
    virtual bool SendData(long lSendip,char *szContent,int nsize);
   // bool SendFile(long lSendip,char *szfilename,int nsize);
    
private:
    INet *m_UDPNet;
    INet *m_TcpNet;
     HWND m_hWnd;
    bool   m_bbusy;
};

Kernel.cpp

#include "stdafx.h"
#include "Kernel.h"
#include "ElectronicResponderClientDlg.h"
 Kernel::Kernel()
 {
     m_UDPNet = new UDPNet(this);
     m_TcpNet = new TCPNet(this);
     Attact(m_UDPNet);
     Attact(m_TcpNet);
     m_bbusy = false;
 }
Kernel::~Kernel()
{
    if(m_UDPNet)
    {
        delete m_UDPNet;
        m_UDPNet = NULL;
    }
    if(m_TcpNet)
    {
        delete m_TcpNet;
        m_TcpNet = NULL;
    }
}

bool  Kernel::Open(HWND hwnd)
{
    if(NULL == hwnd)return false;

    m_hWnd = hwnd;
    //通知启动服务器
    Notify(SY_BEGIN);

    //上线通知

    return true;
}

void  Kernel::Close()
{
    //通知结束服务器
    Notify(SY_END);
    
}
//tcp send file
 /*bool Kernel::SendFile(long lSendip,char *szfilename,int nsize)
 {
     if(!m_TcpNet->SendData(lSendip,szfilename,nsize))
     {
         return false;
     }
     return true;
 }*/
 bool Kernel::SendData(long lSendip,char *szContent,int nsize)
 {
     if(!m_UDPNet->SendData(lSendip,szContent,nsize))
     {
         return false;
     }
     return true;
 }

bool Kernel::RecvData(long lRevip,char *szContent)
{
    int *ptype = (int*)szContent;
    switch (*ptype)
    {
    case PT_REGISTER_RS: //注册回复,提示 注册成功,失败
        {
            STRU_USERINFO_RS *psu = ( STRU_USERINFO_RS *)szContent;
            TCHAR szbuf[10] = {0};
             if(psu->m_bflag)
             {
                 wcscpy_s(szbuf,10,L"注册成功");
             }
             else
             {
                 wcscpy_s(szbuf,10,L"注册失败");
             }
            
             MessageBox(m_hWnd,szbuf,L"温馨提示",MB_OKCANCEL);
        }
        break;
    case PT_LOGIN_RS: //登录回复,
        {
             STRU_USERINFO_RS *psu = ( STRU_USERINFO_RS *)szContent;
             if(psu->m_bflag)
             {
                   PostMessage(m_hWnd,UM_LOGIN,psu->m_bflag,0);
             }
             else
             {
                    MessageBox(m_hWnd,L"登录失败,请重新登录",L"温馨提示",MB_OKCANCEL);
             }
           
        }
        break;
    case PT_ONLINE_RQ://上线请求,显示,并回复
        {
            long lrecvip;
            STRU_BROADCASTINFO *pszbuf = (STRU_BROADCASTINFO *)szContent;
            SendMessage(m_hWnd,UM_ONLINE,pszbuf->m_lHostIp,0);
            if(INet::GetValidIp() == pszbuf->m_lHostIp)
            {
                break;
            }
            lrecvip = pszbuf->m_lHostIp;

            STRU_BROADCASTINFO  sb;
            sb.m_ntype = PT_ONLINE_RS;
            sb.m_lHostIp = INet::GetValidIp();

            m_UDPNet->SendData(lrecvip,(char*)&sb,sizeof(STRU_BROADCASTINFO));
        }
        break;
        case PT_ONLINE_RS://上线回复包
            {
                 STRU_BROADCASTINFO *pszbuf = (STRU_BROADCASTINFO *)szContent;
                 SendMessage(m_hWnd,UM_ONLINE,pszbuf->m_lHostIp,0);
            }
            break;
        case PT_OFFLINE_NTF://下线通知
            {
                 STRU_BROADCASTINFO *pszbuf = (STRU_BROADCASTINFO *)szContent;
                 SendMessage(m_hWnd,UM_OFFLINE,pszbuf->m_lHostIp,0);
            }
            break;
        case PT_DATA: //显示
            {
                STRU_DATAINFO *psd = ( STRU_DATAINFO *)szContent;
                if(psd->m_lhostIp == INet::GetValidIp())
                {
                    break;
                }
                SendMessage(m_hWnd,UM_DATA,(WPARAM)psd->m_szContent,psd->m_lhostIp);
            }
            break;
        case PT_QUICKANSWER: //如果是开始抢答包和停止抢答包
            {
                STRU_QUICKANSWER *psq = (STRU_QUICKANSWER *)szContent;
                TCHAR szbuf[100] = L"请作答:";
                if(psq->m_lHostIp == INet::GetValidIp())
                {
                    SendMessage(m_hWnd,UM_QUICKANSWER,(WPARAM)psq->m_bflag,(LPARAM)szbuf);
                    break;
                }
                SendMessage(m_hWnd,UM_QUICKANSWER,(WPARAM)psq->m_bflag,0);
            }
            break;
        case PT_SUMMITWORK_RS: //提交作业回复,如果教师在线,回复教师ip,否则回复服务器IP
            {
                STRU_SUMMITWORK *pss = (STRU_SUMMITWORK *)szContent;
                //连接这个Ip ,发送文件
                CElectronicResponderClientDlg *pWnd = ( CElectronicResponderClientDlg *)CWnd::FromHandle(m_hWnd);
                m_TcpNet->SendData(pss->m_lHostIp,pWnd->m_strFileName,MAX_PATH);
                 
            }
            break;
          
    default:
        break;
    }
     
    return true;
}


 

5.2.2网络Inet部分

INet.h

#pragma once 

#include "Packdef.h"
#include <winsock2.h>

#pragma comment(lib, "ws2_32.lib")
class INet
{
public:
    INet(){}
    virtual ~INet(){}
public:
    //获得本机Ip地址
    static long GetValidIp()
    {
      
        in_addr addr;
        char szname[20] = {0};
        if(!gethostname(szname,20))
        {
           struct hostent* phost =  gethostbyname(szname);
           if(phost->h_addr_list[0] != 0)
           {
               addr.s_addr = *(u_long *) phost->h_addr_list[0];
                return addr.s_addr;
           }
        }

        return 0;
    }

    virtual bool InitNetWork() = 0;
    virtual bool UnInitNetWork() = 0;
    virtual bool SendData(long lSendIp,char* szbuf,int nlen) = 0;

    virtual void Update(StateType ntype) = 0;
};

TCPNet.h

#pragma once
#include "INet.h"
#include <map>
#include "IKernel.h"
using namespace std;
class TCPNet : public INet
{
public:
	TCPNet(IKernel *pKernel);
	virtual ~TCPNet();
	virtual bool InitNetWork();
	virtual bool UnInitNetWork();
	virtual bool SendData(long lRecvIp,char *szBuffer,int nSize) ;
	//接收连接的线程
	static  unsigned _stdcall  ThreadAccept( void * );
	void Accept();
	//接收数据
	static  unsigned _stdcall  ThreadRecv( void * );
    //接收文件
    static unsigned _stdcall  ThreadSendfile( void * );

    virtual void Update(StateType ntype);
private:
	IKernel *m_pKernel;
	SOCKET m_socketServer;
	HANDLE  m_hThreadAccept;
	HANDLE  m_hEventQuit;
	HANDLE  m_hEventAcceptCheck;
	map<long,SOCKET> m_mapIpToSocket;

	map<long,SOCKET>::iterator  m_itemapIpToSocket;

    long  m_lRecviP;
    char  m_szFileName[MAX_PATH];
};

TCPNet.cpp

#include "stdafx.h"
#include "TCPNet.h"
#include <process.h>
#include <afx.h>
TCPNet::TCPNet(IKernel *pKernel)
{
	m_pKernel = pKernel;
}
TCPNet::~TCPNet()
{
}
void TCPNet::Update(StateType ntype)
{
   
    switch (ntype)
    {
    case SY_BEGIN:
        InitNetWork();
        break;
    case SY_END:
        UnInitNetWork();
        break;
    default:
        break;
    }
}
bool TCPNet::InitNetWork()
{
	WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
    
       
        return false;
    }

                                  

    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
        
        UnInitNetWork();
        return false;
    }
  
	//2.开啦--请一个职业经理 -- 创建socket (套接字)
	m_socketServer = socket(AF_INET ,SOCK_STREAM,IPPROTO_TCP);
	if(INVALID_SOCKET == m_socketServer)
	{
		 UnInitNetWork();
		return false;
	}
	//3.职业经理挂着店名  地址 --bind(IP,端口号)
	
	sockaddr_in addrin;
	addrin.sin_family = AF_INET;
    addrin.sin_port = htons(_DEFAULTPORT); //端口号
	addrin.sin_addr.s_addr = INet::GetValidIp();//ip地址 127.0.0.1
	if(SOCKET_ERROR == bind(m_socketServer,(const sockaddr*)&addrin,sizeof(addrin)))
	{
		UnInitNetWork();
		return false;
	}


	if( SOCKET_ERROR ==listen(m_socketServer,10))
	{
		UnInitNetWork();
		return false;

	}

	m_hEventQuit = CreateEvent(NULL,TRUE,FALSE,NULL);
	m_hEventAcceptCheck = CreateEvent(NULL,TRUE,FALSE,NULL);
	
	m_hThreadAccept =(HANDLE) _beginthreadex(NULL,0,&ThreadAccept,this,0,NULL);

	return true;
}

 unsigned _stdcall  TCPNet::ThreadAccept( void * lpvoid)
 {
	 TCPNet *pthis = (TCPNet*)lpvoid;
	 pthis->Accept();
	 return 0;
 }

 void TCPNet::Accept()
 {
	 while(1)
	 {
		 if(WAIT_OBJECT_0 ==  WaitForSingleObject(m_hEventQuit,100))
		 {
			 break;
		 }
		 SOCKET m_socketWaiter = accept(m_socketServer,NULL,NULL);
		 if(INVALID_SOCKET  == m_socketWaiter)
		 {
			 continue;
		 }
		//接收数据
		 _beginthreadex(NULL,0,&ThreadRecv,(void*)m_socketWaiter,0,0);
			 
	 }

	 SetEvent(m_hEventAcceptCheck);
 }

 unsigned _stdcall  TCPNet::ThreadRecv( void * lpvoid)
 {
	 SOCKET socketClient = (SOCKET )lpvoid;
	 const int nSize = sizeof(STRU_File_BLOCK);
	 char szbuf[nSize] = {0};
	 char szpath[MAX_PATH] = "D:\\作业\\";
	 char szpathTemp[MAX_PATH] = {0};
	 CFile file;
     int nPackSize = 0;
      int nRealRecvNum = 0;
      int noffset = 0;
	 while(1)
	 {
         recv(socketClient,(char*)&nPackSize,sizeof(int),0);
		// Sleep(1);
         while(nPackSize)
         {
            nRealRecvNum = recv(socketClient,szbuf+noffset,nPackSize,0);
            noffset += nRealRecvNum;
            nPackSize -=nRealRecvNum;
         }
		
	//	if(nRealRecvNum >0)
	//	{
			STRU_File_BLOCK *p = (STRU_File_BLOCK *)szbuf;
			//判断包的类型 如果是目录,则创建目录 ,如果是文件则创建文件
			if(p->m_fileType == FT_FILE)
			{
				
				 //创建文件
				if(file.m_hFile == CFile::hFileNull)
				{
					//strcat_s(szpath,MAX_PATH,"\\");
					strcat_s(szpath,MAX_PATH,p->m_szfileName);
                    TCHAR szbuf[260] = {0};
#ifdef _UNICODE
    MultiByteToWideChar(CP_ACP,0,szpath,-1,szbuf,MAX_PATH);
#else
    strcpy_s(szbuf,MAX_PATH,szpath);
#endif
				    file.Open(szbuf,CFile::modeWrite|CFile::modeCreate);
				
				}
				
				  //向文件中写
				file.Write(p->m_szfileContent,p->m_filelen);
				

			}
			//else if(p->m_fileType == F_DIR)
			//{
			//	//创建文件夹并且将文件路径改为
			//	strcat_s(szpath,MAX_PATH,"\\");
			//	strcat_s(szpath,MAX_PATH,p->m_szfileName);
			//	BOOL bSuccess = CreateDirectory(szpath,NULL);
			//	
			//	//strcat_s(szpath,MAX_PATH,p->m_szfileName);
			//	//strcpy_s(szpathTemp,MAX_PATH,szpath);

			//}
			else if(p->m_fileType == FT_END)
			{
				
				file.Close();
			}
		}
		
	 }

	 return 0;
 }
 bool TCPNet::UnInitNetWork()
 {
	 WSACleanup();
	if(m_socketServer)
	{
		closesocket(m_socketServer);
		m_socketServer = NULL;

	}
	
	if(m_hThreadAccept)
	{
		SetEvent(m_hEventQuit);
	
		if(WAIT_OBJECT_0 != WaitForSingleObject(m_hEventAcceptCheck,100))
		{
			TerminateThread(m_hThreadAccept,-1);
			m_hThreadAccept = NULL;
		}
	}

	if(m_hEventQuit)
	{
		CloseHandle(m_hEventQuit);
		m_hEventQuit = NULL;
	}

	if(m_hEventAcceptCheck)
	{
		CloseHandle(m_hEventAcceptCheck);
		m_hEventAcceptCheck = NULL;
	}
	if(m_hThreadAccept)
	{
		CloseHandle(m_hThreadAccept);
		m_hThreadAccept = NULL;
	}

    return true;

 }

 bool TCPNet::SendData(long lRecvIp,char *szBuffer,int nSize) 
 {
	 //判断当前是否有连接,如果有则直接发送数据,否则创建连接在发送数据
     m_lRecviP = lRecvIp;
     strcpy_s(m_szFileName,nSize,szBuffer);
    HANDLE hThread = (HANDLE)_beginthreadex(NULL,0,&ThreadSendfile,this,0,NULL);
    if(hThread)
    {
        CloseHandle(hThread);
        hThread = NULL;
    }
	
    

	return true;
 }

 unsigned _stdcall  TCPNet::ThreadSendfile( void *lpvoid )
 {
     TCPNet *pthis = ( TCPNet *)lpvoid;
     SOCKET sock = NULL;
     int nsize = sizeof(STRU_File_BLOCK);
     //file.Open();
    sock = socket(AF_INET ,SOCK_STREAM,IPPROTO_TCP);
	if(INVALID_SOCKET == sock)return false;
	sockaddr_in addrin;
	addrin.sin_family = AF_INET;
    addrin.sin_port = htons(_DEFAULTPORT); //端口号
    addrin.sin_addr.s_addr = pthis->m_lRecviP;//ip地址 127.0.0.1
	if(SOCKET_ERROR == connect(sock,(const sockaddr*)&addrin,sizeof(addrin)))
	{
		return false;
	}
     STRU_File_BLOCK sf;
     sf.m_fileType = FT_FILE;
		//打开文件
      TCHAR szbuf[260] = {0};
#ifdef _UNICODE
    MultiByteToWideChar(CP_ACP,0,pthis->m_szFileName,-1,szbuf,100);
#else
    strcpy_s(szbuf,100,pthis->m_szFileName);
#endif
         CFile file(szbuf,CFile::modeRead);

		//获得当前路径下的文件名
         char *ptemp = pthis->m_szFileName;
         while(*ptemp++ != '\0');
         while(*(--ptemp) != '\0');
         ptemp++;
		
		strcpy_s(sf.m_szfileName,MAX_PATH,ptemp);

		while(1)
		{
			//读文件内容
			int nRelReadNum = file.Read(sf.m_szfileContent,sizeof(sf.m_szfileContent));
                     
			if(nRelReadNum >0)
			{
				//发送
			     sf.m_filelen = nRelReadNum;
                 send(sock,(const char*)&nsize,sizeof(int),0);
				// send(sock,(const char*)&nRelReadNum,sizeof(int),0);
                 send(sock,(const char*)&sf,sizeof(STRU_File_BLOCK),0);
			}
			else
			{
				break;
			}
		
		}
		
		file.Close();
		//再去发送结束包
		STRU_File_BLOCK sfend;
		sfend.m_fileType = FT_END;
        send(sock,(char*)&nsize,sizeof(int),0);
		send(sock,(char*)&sfend,sizeof(sfend),0);
	
        closesocket(sock);
        return 0;
 }
 

UDPNet.h

#include "INet.h"
#include "IKernel.h"
class UDPNet :public INet
{
public:
    UDPNet(IKernel *pKernel);
    virtual ~UDPNet();
public:
   
    virtual bool InitNetWork();
    virtual bool UnInitNetWork();
    virtual bool SendData(long lSendIp,char* szbuf,int nlen);

    virtual void Update(StateType ntype);

    static unsigned _stdcall ThreadProc( void * lpvoid);
    void RecvData();
    bool  SelectSocket(SelectType ntype,SOCKET sock);
private:
    SOCKET m_sockListen;
    HANDLE m_hThread;
    bool   m_bFlagQuit;
    IKernel *m_pKernel;

};

UDPNet.cpp

#include "stdafx.h"
#include "UDPNet.h"
#include <process.h>
UDPNet::UDPNet(IKernel *pKernel)
{
    m_sockListen = NULL;
    m_hThread = NULL;
    m_bFlagQuit = false;
    m_pKernel = pKernel;
}
UDPNet::~UDPNet()
{

}
bool UDPNet::InitNetWork()
{
    //1.选择店规模  -- 加载库

	 WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
    
      
        return false;
    }



    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
        UnInitNetWork();
        return false;
    }

	//2.创建店。店长 -- 创建套接字socket 
	m_sockListen = socket(AF_INET,SOCK_DGRAM  ,IPPROTO_UDP);
	if(INVALID_SOCKET  == m_sockListen)
	{
		UnInitNetWork();
        return false;
	}
	//3.绑定信息(店名,地址,电话)-绑定(ip,端口号)bind 
	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr =GetValidIp();
	addr.sin_port = htons(_DEFAULTPORT);
	if(SOCKET_ERROR == bind(m_sockListen,(const sockaddr*)&addr,sizeof(sockaddr_in)))
	{
		UnInitNetWork();
        return false;
	}

	//广播属性
	bool optval = true;
	setsockopt(m_sockListen,SOL_SOCKET,SO_BROADCAST,(const char*)&optval,sizeof(bool));

    //接收数据--I/O select 
    m_bFlagQuit = true;
    m_hThread = (HANDLE) _beginthreadex(NULL,0,&ThreadProc,this,0,NULL);

    return true;
}

unsigned _stdcall UDPNet::ThreadProc( void * lpvoid)
{
    UDPNet *pthis = (UDPNet *)lpvoid;
    pthis->RecvData();
   
    return 0;
}

 bool  UDPNet::SelectSocket(SelectType ntype,SOCKET sock)
 {
     TIMEVAL tv;
     tv.tv_sec = 0;
     tv.tv_usec = 100;
     //1.创建集合
     fd_set fdsets;
     //2.清空集合
     FD_ZERO(&fdsets);
     //3.将socket 放入集合内
     FD_SET(sock,&fdsets);
     //4.将集合交给SELECT 去管理
     if(ntype == ST_READ)
     {
         select(NULL,&fdsets,NULL,NULL,&tv);
     }
     else  if(ntype == ST_WRITE)
     {
          select(NULL,NULL,&fdsets,NULL,&tv);
     }

     //5.检验socket 是否发生网络事件
     if(!FD_ISSET(sock,&fdsets))
     {
         return false;
     }

     return true;
 }

void UDPNet::RecvData()
{
    char szbuf[_DEFAULTPACKEF] = {0};
    sockaddr_in addr;
    int nsize;
     while(m_bFlagQuit)
    {
         nsize = sizeof(sockaddr_in);
        //接收数据
        if(SelectSocket(ST_READ,m_sockListen))
        {
            int nres = recvfrom(m_sockListen,szbuf,_DEFAULTPACKEF,0,(sockaddr*)&addr,&nsize);
            if(nres > 0 )
            {
                //交给Kernel 处理
                m_pKernel->RecvData(addr.sin_addr.s_addr,szbuf);

            }
        }
      
    }
}

bool UDPNet::UnInitNetWork()
{
    WSACleanup();
    if(m_sockListen)
    {
        closesocket(m_sockListen);
        m_sockListen = NULL;
    }

    if(m_hThread)
    {
        m_bFlagQuit = false;
        if(WAIT_TIMEOUT ==  WaitForSingleObject(m_hThread,100))
        {
            TerminateThread(m_hThread,-1);
        }

        CloseHandle(m_hThread);
        m_hThread = NULL;
    }

    return true;
}

bool UDPNet::SendData(long lSendIp,char* szbuf,int nlen)
{

    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(_DEFAULTPORT);
    addr.sin_addr.S_un.S_addr = lSendIp;

    if(sendto(m_sockListen,szbuf,nlen,0,(const sockaddr*)&addr,sizeof(addr)) <= 0)
    {
        return false;
    }

    return true;
}

void UDPNet::Update(StateType ntype)
{
   
    switch (ntype)
    {
    case SY_BEGIN:
        InitNetWork();
        break;
    case SY_END:
        UnInitNetWork();
        break;
    default:
        break;
    }
}

5.2.3数据包部分

Packdef.h

#ifndef _PACKDEF_H
#define _PACKDEF_H 

#define _DEFAULTPORT  1234

#define _DEFAULTPACKEF    1024
#define _DEFAULTSIZE      200

#define _DEFAULTNUM        20
#define ONE_PAGE          4096

//消息类型
#define UM_LOGIN       WM_USER + 1
#define UM_ONLINE      WM_USER + 2 
#define UM_OFFLINE     WM_USER + 3
#define UM_DATA        WM_USER + 4
#define UM_QUICKANSWER        WM_USER + 5
//执行标识
enum  StateType{SY_BEGIN,SY_END};

//select 管理缓冲区的类型  
enum  SelectType{ST_WRITE,ST_READ};

//包类型
enum  PackType{PT_REGISTER_RQ,PT_REGISTER_RS,PT_LOGIN_RQ,PT_LOGIN_RS,
               PT_ONLINE_RQ, PT_ONLINE_RS,PT_OFFLINE_NTF,PT_QUICKANSWER,
               PT_DATA,PT_ANSWER_RACE,PT_SUMMITWORK_RQ,PT_SUMMITWORK_RS};
//协议包
//注册包。登录包
struct STRU_USERINFO
{
    STRU_USERINFO()
    {
        m_ntype = PT_REGISTER_RQ;
        ZeroMemory(m_szUserName,_DEFAULTNUM);
        ZeroMemory(m_szPassWord,_DEFAULTNUM);
        ZeroMemory(m_szRole,_DEFAULTNUM);
        ZeroMemory(m_szCheck,_DEFAULTNUM);
       
    }
    PackType  m_ntype; 
    char      m_szUserName[_DEFAULTNUM];
    char      m_szPassWord[_DEFAULTNUM];
    char      m_szRole[_DEFAULTNUM];
    char      m_szCheck[_DEFAULTNUM];
};

//注册、登录 回复包
struct STRU_USERINFO_RS
{
    STRU_USERINFO_RS()
    {
        m_ntype = PT_REGISTER_RS;
        m_bflag = 0;
    }
   PackType  m_ntype; 
   bool      m_bflag;

};

//上线。xiaxian 

struct STRU_BROADCASTINFO
{
    STRU_BROADCASTINFO()
    {
        m_ntype = PT_ONLINE_RQ;
        m_lHostIp = 0;
        m_lTargetIp = 0;
    }
     PackType  m_ntype; 
     long      m_lHostIp;
     long      m_lTargetIp;

};

//快速抢答 -- 开始抢答,停止抢答,教师收到自己发的包不需要处理
struct STRU_QUICKANSWER
{
    STRU_QUICKANSWER()
    {
        m_ntype = PT_QUICKANSWER;
        m_bflag = 1;
        m_lHostIp = 0;
    }
     PackType  m_ntype; 
     bool      m_bflag; 
     long      m_lHostIp;

};
////停止扩展包---这个是为了学生抢答完成,服务器告诉所有人停止抢答--这个协议包可以删除--待考虑
//struct STRU_QUICKANSWEREX
//{
//    STRU_QUICKANSWEREX()
//    {
//        m_ntype = PT_QUICKANSWER;
//        m_bflag = 1;
//        m_lip = 0;
//    }
//     PackType  m_ntype; 
//     bool      m_bflag; 
//     long      m_lip;
//
//};

//数据包--发送

struct STRU_DATAINFO
{
  STRU_DATAINFO()
  {
      m_ntype = PT_DATA;
      ZeroMemory(m_szContent,_DEFAULTSIZE);
      m_lhostIp = 0;
  }
   PackType  m_ntype; 
   char      m_szContent[_DEFAULTSIZE];
   long      m_lhostIp;

};

//我要抢答 --个人信息,
struct STRU_ANSWER_RACE
{
    STRU_ANSWER_RACE()
    {
        m_ntype = PT_ANSWER_RACE;
        m_lHostIp = 0;
    }
    PackType  m_ntype; 
    long      m_lHostIp;
};

//提交作业
struct STRU_SUMMITWORK
{

   STRU_SUMMITWORK()
    {
        m_ntype = PT_SUMMITWORK_RQ;
        m_lHostIp = 0;
    }
    PackType  m_ntype; 
    long      m_lHostIp;
};
enum FileType{FT_FILE,FT_END};
//文件块
struct  STRU_File_BLOCK
{
public:
	STRU_File_BLOCK()
	{
		ZeroMemory(m_szfileName,MAX_PATH);
		ZeroMemory(m_szfileContent,ONE_PAGE);
		m_filelen = 0;
		//m_fileType = F_UNKOWN;
	}
public:
	char m_szfileName[MAX_PATH];
	char m_szfileContent[ONE_PAGE];
	int  m_filelen;
	FileType m_fileType;
};


#endif

5.2.4main部分

CElectronicResponderClientDlg.h

// ElectronicResponderClientDlg.h : 头文件
//

#pragma once
#include "resource.h"
#include "afxwin.h"

// CElectronicResponderClientDlg 对话框
class CElectronicResponderClientDlg : public CDialogEx
{
// 构造
public:
	CElectronicResponderClientDlg(CWnd* pParent = NULL);	// 标准构造函数

// 对话框数据
	enum { IDD = IDD_DLG_STUDENT };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
    afx_msg LRESULT OnLineMsg(WPARAM wparam,LPARAM lparam);
    afx_msg LRESULT OffLineMsg(WPARAM wparam,LPARAM lparam);
    afx_msg LRESULT ShowDataMsg(WPARAM wparam,LPARAM lparam);
    afx_msg LRESULT QuickAnswerMsg(WPARAM wparam,LPARAM lparam);
	DECLARE_MESSAGE_MAP()
public:
    CListBox m_lstData;
    CEdit m_lstSend;
    CListBox m_lstIp;
    char m_strFileName[MAX_PATH];
    afx_msg void OnBnClickedButton4();
    afx_msg void OnDestroy();
    afx_msg void OnBnClickedButton1();
    afx_msg void OnBnClickedButSumitwork();
};

CElectronicResponderClientDlg.cpp

// ElectronicResponderClientDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "ElectronicResponderClient.h"
#include "ElectronicResponderClientDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CElectronicResponderClientDlg 对话框



CElectronicResponderClientDlg::CElectronicResponderClientDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CElectronicResponderClientDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CElectronicResponderClientDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_LIST1, m_lstData);
    DDX_Control(pDX, IDC_EDIT1, m_lstSend);
    DDX_Control(pDX, IDC_LIST2, m_lstIp);
}

BEGIN_MESSAGE_MAP(CElectronicResponderClientDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
    ON_MESSAGE(UM_ONLINE,&CElectronicResponderClientDlg::OnLineMsg)
    ON_MESSAGE(UM_OFFLINE,&CElectronicResponderClientDlg::OffLineMsg)
    ON_MESSAGE(UM_DATA,&CElectronicResponderClientDlg::ShowDataMsg)
    ON_MESSAGE(UM_QUICKANSWER,&CElectronicResponderClientDlg::QuickAnswerMsg)

    ON_BN_CLICKED(IDC_BUT_SEND, &CElectronicResponderClientDlg::OnBnClickedButton4)
    ON_WM_DESTROY()
    ON_BN_CLICKED(IDC_BUT_QUICKANSWER, &CElectronicResponderClientDlg::OnBnClickedButton1)
    ON_BN_CLICKED(IDC_BUT_SUMITWORK, &CElectronicResponderClientDlg::OnBnClickedButSumitwork)
END_MESSAGE_MAP()


// CElectronicResponderClientDlg 消息处理程序

BOOL CElectronicResponderClientDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标
 GetDlgItem(IDC_BUT_SEND)->EnableWindow(0);
    GetDlgItem(IDC_BUT_QUICKANSWER)->EnableWindow(0);
           ((Kernel*)theApp.m_pKernel)->SetHwnd( theApp.m_pMainWnd->m_hWnd);
	// TODO: 在此添加额外的初始化代码
      //广播上线
    STRU_BROADCASTINFO sb;
    sb.m_lHostIp = INet::GetValidIp();
    theApp.m_pKernel->SendData(inet_addr("192.168.1.252"),(char*)&sb,sizeof(STRU_BROADCASTINFO));
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CElectronicResponderClientDlg::OnDestroy()
{
    CDialogEx::OnDestroy();

    // TODO: 在此处添加消息处理程序代码
     STRU_BROADCASTINFO sb;
    sb.m_ntype = PT_OFFLINE_NTF;
    sb.m_lHostIp = INet::GetValidIp();
    theApp.m_pKernel->SendData(inet_addr("192.168.1.252"),(char*)&sb,sizeof(STRU_BROADCASTINFO));
}


//上线
LRESULT CElectronicResponderClientDlg::OnLineMsg(WPARAM wparam,LPARAM lparam)
{
    //将Ip 转为字符串
    in_addr addr;
    addr.S_un.S_addr = wparam;
    char *szip =  inet_ntoa(addr);
    TCHAR szbuf[100] = {0};
#ifdef _UNICODE
    MultiByteToWideChar(CP_ACP,0,szip,-1,szbuf,100);
#else
    strcpy_s(szbuf,100,szip);
#endif
   
    m_lstIp.AddString(szbuf);
    return 0;
}
//下线
LRESULT CElectronicResponderClientDlg::OffLineMsg(WPARAM wparam,LPARAM lparam)
 {
    //将Ip 转为字符串
    in_addr addr;
    addr.S_un.S_addr = wparam;
    char *szip =  inet_ntoa(addr);
    CString strIP;
    TCHAR szbuf[100] = {0};
#ifdef _UNICODE
    MultiByteToWideChar(CP_ACP,0,szip,-1,szbuf,100);
#else
    strcpy_s(szbuf,100,szip);
#endif
    for(int i = 0; i < m_lstIp.GetCount();i++ )
    {
        m_lstIp.GetText(i,strIP);
        if(!_tcscmp(szbuf,strIP))
        {
            m_lstIp.DeleteString(i);
            break;
        }
    }
     return 0;
 }

 //显示数据
 LRESULT CElectronicResponderClientDlg::ShowDataMsg(WPARAM wparam,LPARAM lparam)
 {
     char *pContent =(char*)wparam;
     //IP :
    in_addr addr;
    addr.S_un.S_addr = lparam;
    char *szip =  inet_ntoa(addr);
    CString strIP;
    TCHAR szbufIP[100] = {0};
    TCHAR szContent[_DEFAULTSIZE] = {0};
#ifdef _UNICODE
    MultiByteToWideChar(CP_ACP,0,szip,-1,szbufIP,100);
    MultiByteToWideChar(CP_ACP,0,pContent,-1,szContent,_DEFAULTSIZE);
#else
    strcpy_s(szbufIP,100,szip);
    strcpy_s(szContent,_DEFAULTSIZE,pContent);
#endif

    m_lstData.AddString(szbufIP);
    m_lstData.AddString(szContent);

     return 0;
 }

 //是否可以抢答
LRESULT CElectronicResponderClientDlg::QuickAnswerMsg(WPARAM wparam,LPARAM lparam)
{
    //如果lparam有值,则代表已经抢到,可以开始答题
    TCHAR *szbuf= (TCHAR*)lparam;
    if(szbuf)
    {
        m_lstData.AddString(_T("系统提示:请您开始抢答"));
        return 0;
    }
    //如果wparam --为1 则按钮可用  否则不可用
    GetDlgItem(IDC_BUT_SEND)->EnableWindow(wparam);
    GetDlgItem(IDC_BUT_QUICKANSWER)->EnableWindow(wparam);
   if(wparam)
   {
       m_lstData.AddString(_T("系统提示:开始抢答"));
   }
   
    return 0;
}
//我要抢答
void CElectronicResponderClientDlg::OnBnClickedButton1()
{
    // TODO: 在此添加控件通知处理程序代码
    STRU_ANSWER_RACE sa;
    sa.m_lHostIp  = INet::GetValidIp();
    theApp.m_pKernel->SendData(inet_addr("192.168.1.252"),(char*)&sa,sizeof(STRU_ANSWER_RACE));
      
}

 //发送数据
void CElectronicResponderClientDlg::OnBnClickedButton4()
{
    // TODO: 在此添加控件通知处理程序代码
      CString str;
    m_lstSend.GetWindowText(str);
    STRU_DATAINFO sd;
    sd.m_lhostIp =INet::GetValidIp();

     TCHAR szbuf[100] = {0};
#ifdef _UNICODE
     WideCharToMultiByte(CP_ACP,0,str,-1,sd.m_szContent,_DEFAULTSIZE,0,0);
#else
    strcpy_s(sd.m_szContent,_DEFAULTSIZE,str);
#endif  

    
    theApp.m_pKernel->SendData(inet_addr("192.168.1.252"),(char*)&sd,sizeof(STRU_DATAINFO));
      

    m_lstData.AddString(_T("我说:"));
    m_lstData.AddString(str);
}


void CElectronicResponderClientDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CElectronicResponderClientDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CElectronicResponderClientDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}







//提交作业
void CElectronicResponderClientDlg::OnBnClickedButSumitwork()
{
    // TODO: 在此添加控件通知处理程序代码
    CFileDialog dlg(TRUE);
    if(IDOK == dlg.DoModal())
    {
     
     
#ifdef _UNICODE
     WideCharToMultiByte(CP_ACP,0,dlg.GetPathName(),-1,m_strFileName,MAX_PATH,0,0);
#else
    strcpy_s(m_strFileName,MAX_PATH,dlg.GetPathName());
#endif  
       
        STRU_SUMMITWORK ss;
        ss.m_lHostIp = INet::GetValidIp();

        theApp.m_pKernel->SendData(inet_addr("192.168.1.252"),(char*)&ss,sizeof(STRU_SUMMITWORK));
    }
   
}

CMyLogin.h

#pragma once

// CMyLogin 对话框

class CMyLogin : public CDialogEx
{
	DECLARE_DYNAMIC(CMyLogin)

public:
	CMyLogin(CWnd* pParent = NULL);   // 标准构造函数
	virtual ~CMyLogin();

// 对话框数据
	enum { IDD = IDD_DLG_LOGIN };

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    afx_msg LRESULT OnLoginMsg(WPARAM wparam,LPARAM lparam);
	DECLARE_MESSAGE_MAP()
public:
    virtual BOOL OnInitDialog();
    afx_msg void OnBnClickedButton1();
    CString m_edtUserName;
    CString m_edtPassWord;
    CString m_comRole;
    CString m_edtCheck;
    afx_msg void OnBnClickedButton2();
};

CMyLogin.cpp

// MyLogin.cpp : 实现文件
//

#include "stdafx.h"
#include "ElectronicResponderClient.h"
#include "MyLogin.h"
#include "afxdialogex.h"
#include "Packdef.h"
#include "ElectronicResponderClientDlg.h"
#include "MyTeacher.h"
// CMyLogin 对话框

IMPLEMENT_DYNAMIC(CMyLogin, CDialogEx)

CMyLogin::CMyLogin(CWnd* pParent /*=NULL*/)
	: CDialogEx(CMyLogin::IDD, pParent)
    , m_edtUserName(_T(""))
    , m_edtPassWord(_T(""))
    , m_comRole(_T(""))
    , m_edtCheck(_T(""))
{
    theApp.m_pKernel = new Kernel;
}

CMyLogin::~CMyLogin()
{
    if(theApp.m_pKernel)
    {
        delete theApp.m_pKernel;
        theApp.m_pKernel = NULL;
    }
}

void CMyLogin::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Text(pDX, IDC_EDT_USERNAME, m_edtUserName);
    DDX_Text(pDX, IDC_EDT_PASSWORD, m_edtPassWord);
    DDX_CBString(pDX, IDC_COM_ROLE, m_comRole);
    DDX_Text(pDX, IDC_EDT_CHECK, m_edtCheck);
}


BEGIN_MESSAGE_MAP(CMyLogin, CDialogEx)
    ON_BN_CLICKED(IDC_BUTTON1, &CMyLogin::OnBnClickedButton1)
    ON_BN_CLICKED(IDC_BUTTON2, &CMyLogin::OnBnClickedButton2)
    ON_MESSAGE(UM_LOGIN,&CMyLogin::OnLoginMsg)
END_MESSAGE_MAP()


// CMyLogin 消息处理程序


BOOL CMyLogin::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    GetDlgItem(IDC_BUTTON2)->EnableWindow(0);

    theApp.m_pKernel->Open(m_hWnd);
    return TRUE;  // return TRUE unless you set the focus to a control

}

LRESULT CMyLogin::OnLoginMsg(WPARAM wparam,LPARAM lparam)
{
    //判断当前身份,
    if(m_comRole == "student")
    {
            CElectronicResponderClientDlg dlg;
            theApp.m_pMainWnd = &dlg;
            
              CDialogEx::OnOK();

              dlg.DoModal();
    }
    else
    {
            CMyTeacher dlg;
            theApp.m_pMainWnd = &dlg;
            // ((Kernel*)theApp.m_pKernel)->SetHwnd( theApp.m_pMainWnd->m_hWnd);
             CDialogEx::OnOK();

             dlg.DoModal();

    }

   
  
    return 0;
}

void CMyLogin::OnBnClickedButton1()
{
    // TODO: 在此添加控件通知处理程序代码
    //获得用户信息
    UpdateData(TRUE);
    
    STRU_USERINFO su;
  
#ifdef _UNICODE

    WideCharToMultiByte(CP_ACP,0,m_edtUserName,-1,su.m_szUserName,_DEFAULTNUM,0,0);
    WideCharToMultiByte(CP_ACP,0,m_edtPassWord,-1,su.m_szPassWord,_DEFAULTNUM,0,0);
    WideCharToMultiByte(CP_ACP,0,m_comRole,-1,su.m_szRole,_DEFAULTNUM,0,0);
#else
    strcpy_s(su.m_szUserName,_DEFAULTNUM,m_edtUserName);
    strcpy_s(su.m_szPassWord,_DEFAULTNUM,m_edtPassWord);
    strcpy_s(su.m_szRole,_DEFAULTNUM,m_comRole);
#endif

    theApp.m_pKernel->SendData(inet_addr("192.168.1.252"),(char*)&su,sizeof(STRU_USERINFO));


}


void CMyLogin::OnBnClickedButton2()
{
    // TODO: 在此添加控件通知处理程序代码
      //获得用户信息
    UpdateData(TRUE);
    
    STRU_USERINFO su;
    su.m_ntype = PT_LOGIN_RQ;
#ifdef _UNICODE

    WideCharToMultiByte(CP_ACP,0,m_edtUserName,-1,su.m_szUserName,_DEFAULTNUM,0,0);
    WideCharToMultiByte(CP_ACP,0,m_edtPassWord,-1,su.m_szPassWord,_DEFAULTNUM,0,0);
    WideCharToMultiByte(CP_ACP,0,m_comRole,-1,su.m_szRole,_DEFAULTNUM,0,0);
#else
    strcpy_s(su.m_szUserName,_DEFAULTNUM,m_edtUserName);
    strcpy_s(su.m_szPassWord,_DEFAULTNUM,m_edtPassWord);
    strcpy_s(su.m_szRole,_DEFAULTNUM,m_comRole);
#endif

    theApp.m_pKernel->SendData(inet_addr("192.168.1.252"),(char*)&su,sizeof(STRU_USERINFO));
}

CMyTeacher.h

#pragma once
#include "afxwin.h"


// CMyTeacher 对话框

class CMyTeacher : public CDialogEx
{
	DECLARE_DYNAMIC(CMyTeacher)

public:
	CMyTeacher(CWnd* pParent = NULL);   // 标准构造函数
	virtual ~CMyTeacher();

// 对话框数据
	enum { IDD = IDD_DLG_TEACHER };

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    afx_msg LRESULT OnLineMsg(WPARAM wparam,LPARAM lparam);
    afx_msg LRESULT OffLineMsg(WPARAM wparam,LPARAM lparam);
    afx_msg LRESULT ShowDataMsg(WPARAM wparam,LPARAM lparam);
    afx_msg void OnBnClickedButton1();//开始抢答
    afx_msg void OnBnClickedButton3();//停止抢答
    afx_msg void OnBnClickedButton4();//发送数据
    virtual BOOL OnInitDialog();
    afx_msg void OnDestroy();
	DECLARE_MESSAGE_MAP()
public:
  
   
    CListBox m_lstIp;
    CListBox m_lstData;

    CEdit m_edtSend;
   
};

CMyTeacher.cpp

// MyTeacher.cpp : 实现文件
//

#include "stdafx.h"
#include "ElectronicResponderClient.h"
#include "MyTeacher.h"
#include "afxdialogex.h"
#include "ElectronicResponderClient.h"

// CMyTeacher 对话框

IMPLEMENT_DYNAMIC(CMyTeacher, CDialogEx)

CMyTeacher::CMyTeacher(CWnd* pParent /*=NULL*/)
	: CDialogEx(CMyTeacher::IDD, pParent)
{

}

CMyTeacher::~CMyTeacher()
{
}

void CMyTeacher::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_LIST2, m_lstIp);
    DDX_Control(pDX, IDC_EDIT1, m_edtSend);
    DDX_Control(pDX, IDC_LIST1, m_lstData);
}


BEGIN_MESSAGE_MAP(CMyTeacher, CDialogEx)
    ON_BN_CLICKED(IDC_BUTTON1, &CMyTeacher::OnBnClickedButton1)
    ON_WM_DESTROY()
    ON_MESSAGE(UM_ONLINE,&CMyTeacher::OnLineMsg)
    ON_MESSAGE(UM_OFFLINE,&CMyTeacher::OffLineMsg)
    ON_MESSAGE(UM_DATA,&CMyTeacher::ShowDataMsg)
    ON_BN_CLICKED(IDC_BUTTON3, &CMyTeacher::OnBnClickedButton3)
    ON_BN_CLICKED(IDC_BUTTON4, &CMyTeacher::OnBnClickedButton4)
END_MESSAGE_MAP()


// CMyTeacher 消息处理程序
//初始化
BOOL CMyTeacher::OnInitDialog()
{
    CDialogEx::OnInitDialog();
  ((Kernel*)theApp.m_pKernel)->SetHwnd( theApp.m_pMainWnd->m_hWnd);
    //广播上线
    STRU_BROADCASTINFO sb;
    sb.m_lHostIp = INet::GetValidIp();
    theApp.m_pKernel->SendData(inet_addr("192.168.1.252"),(char*)&sb,sizeof(STRU_BROADCASTINFO));

   // GetDlgItem(IDC_BUTTON3)->EnableWindow(0);
    return TRUE;  // return TRUE unless you set the focus to a control

    // 异常: OCX 属性页应返回 FALSE
}

//结束
void CMyTeacher::OnDestroy()
{
    CDialogEx::OnDestroy();
    STRU_BROADCASTINFO sb;
    sb.m_ntype = PT_OFFLINE_NTF;
    sb.m_lHostIp = INet::GetValidIp();
    theApp.m_pKernel->SendData(inet_addr("192.168.1.252"),(char*)&sb,sizeof(STRU_BROADCASTINFO));
    // TODO: 在此处添加消息处理程序代码
}


//开始抢答

void CMyTeacher::OnBnClickedButton1()
{
    // TODO: 在此添加控件通知处理程序代码
    STRU_QUICKANSWER sq;
    sq.m_bflag = 1;

    theApp.m_pKernel->SendData(inet_addr("192.168.1.252"),(char*)&sq,sizeof(STRU_QUICKANSWER));
    //
}
//停止抢答
void CMyTeacher::OnBnClickedButton3()
{
    // TODO: 在此添加控件通知处理程序代码
    //停止抢答
    STRU_QUICKANSWER sq;
    sq.m_bflag = 0;
    sq.m_lHostIp = INet::GetValidIp();
    theApp.m_pKernel->SendData(inet_addr("192.168.1.252"),(char*)&sq,sizeof(STRU_QUICKANSWER));
}

//上线
LRESULT CMyTeacher::OnLineMsg(WPARAM wparam,LPARAM lparam)
{
    //将Ip 转为字符串
    in_addr addr;
    addr.S_un.S_addr = wparam;
    char *szip =  inet_ntoa(addr);
    TCHAR szbuf[100] = {0};
#ifdef _UNICODE
    MultiByteToWideChar(CP_ACP,0,szip,-1,szbuf,100);
#else
    strcpy_s(szbuf,100,szip);
#endif
   
    m_lstIp.AddString(szbuf);
    return 0;
}
//下线
 LRESULT CMyTeacher::OffLineMsg(WPARAM wparam,LPARAM lparam)
 {
    //将Ip 转为字符串
    in_addr addr;
    addr.S_un.S_addr = wparam;
    char *szip =  inet_ntoa(addr);
    CString strIP;
    TCHAR szbuf[100] = {0};
#ifdef _UNICODE
    MultiByteToWideChar(CP_ACP,0,szip,-1,szbuf,100);
#else
    strcpy_s(szbuf,100,szip);
#endif
    for(int i = 0; i < m_lstIp.GetCount();i++ )
    {
        m_lstIp.GetText(i,strIP);
        if(!_tcscmp(szbuf,strIP))
        {
            m_lstIp.DeleteString(i);
            break;
        }
    }
     return 0;
 }

 //显示数据
 LRESULT CMyTeacher::ShowDataMsg(WPARAM wparam,LPARAM lparam)
 {
     char *pContent =(char*)wparam;
     //IP :
    in_addr addr;
    addr.S_un.S_addr = lparam;
    char *szip =  inet_ntoa(addr);
    CString strIP;
    TCHAR szbufIP[100] = {0};
    TCHAR szContent[_DEFAULTSIZE] = {0};
#ifdef _UNICODE
    MultiByteToWideChar(CP_ACP,0,szip,-1,szbufIP,100);
    MultiByteToWideChar(CP_ACP,0,pContent,-1,szContent,_DEFAULTSIZE);
#else
    strcpy_s(szbufIP,100,szip);
    strcpy_s(szContent,_DEFAULTSIZE,pContent);
#endif

    m_lstData.AddString(szbufIP);
    m_lstData.AddString(szContent);

     return 0;
 }

//发送数据

void CMyTeacher::OnBnClickedButton4()
{
    // TODO: 在此添加控件通知处理程序代码
    CString str;
    m_edtSend.GetWindowText(str);
    STRU_DATAINFO sd;
    sd.m_lhostIp =INet::GetValidIp();

     TCHAR szbuf[100] = {0};
#ifdef _UNICODE
     WideCharToMultiByte(CP_ACP,0,str,-1,sd.m_szContent,_DEFAULTSIZE,0,0);
#else
    strcpy_s(sd.m_szContent,_DEFAULTSIZE,str);
#endif  

    
    theApp.m_pKernel->SendData(inet_addr("192.168.1.252"),(char*)&sd,sizeof(STRU_DATAINFO));
      

    m_lstData.AddString(_T("我说:"));
    m_lstData.AddString(str);
}


猜你喜欢

转载自blog.csdn.net/qq_35703848/article/details/79724346