第 64 章
数及其说明
成员函数 说明
BOOL ConnectSocket(LPCTSTR lpszHandle,
LPCTSTR lpszAddress, int nPort)
连接服务器,3 个参数依次是用户名、服务器地址
和端口号
枫叶文学网www.fywxw.com
第11 章 网络编程
·315·
续表
成员函数 说明
void ProcessReceive() 当接收到信息时调用此函数,进行信息接收等cāo作
void SendMsg(CString& strText, int mCode, BOOL
bSendNcom)
发送信息,3 个参数分别表示信息内容、信息种类
和是否发送用户名
void ReceiveMsg() 接收信息
void DisplayMsg(LPCTSTR lpszText) 显示信息
void UpdateChattersList(CMsg* pMsg) 更新用户列表
virtual void DeleteContents() 断开时所作的工作
下面开始为各函数编写代码。
首先在构造函数中将各成员变量初始化,代码如下:
CChatClientDoc::CChatClientDoc()
{
// TODO: add one-tcom construction code here
bIsConnected = FALSE;
m_pSocket = NULL;
m_pFile = NULL;
m_pArchiveOut = NULL;
m_pArchiveIn = NULL;
}
接着为“连接”菜单项编写响应函数,代码如下:
void CChatClientDoc::OnConnect()
{
// TODO: Add your command handler code here
CLogDlg dlg;
if(dlg.DoModal() == IDOK)
{
if(ConnectSocket(dlg.m_Ncom, dlg.m_Server, dlg.m_Port))
bIsConnected = TRUE;
else
AfxMessageBox("连接服务器失败!");
}
}
当连接后,应该使“连接”菜单项无效,为消息UPDATA_COMMAND_UI 添加响应函
数如下:
void CChatClientDoc::OnUpdateConnect(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->Enable(!bIsConnected);
}
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·316·
为“断开”菜单项添加响应函数,代码如下:
void CChatClientDoc::OnDisconnect()
{
// TODO: Add your command handler code here
DeleteContents();
bIsConnected = FALSE;
}
当断开后,应当使“断开”菜单项无效,为消息UPDATA_COMMAND_UI 添加如下响
应函数:
void CChatClientDoc::OnUpdateDisconnect(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->Enable(bIsConnected);
}
为ConnectSocket()函数编写如下代码:
BOOL CChatClientDoc::ConnectSocket(LPCTSTR lpszHandle, LPCTSTR lpszAddress, int nPort)
{
m_strNcom = lpszHandle;
m_pSocket = new CChatSocket(this);
//创建socket 失败
if (!m_pSocket->Create())
{
delete m_pSocket;
m_pSocket = NULL;
AfxMessageBox("创建socket 失败!");
return FALSE;
}
//连接失败
if(!m_pSocket->Connect(lpszAddress, nPort))
{
delete m_pSocket;
m_pSocket = NULL;
return FALSE;
}
m_pFile = new CSocketFile(m_pSocket);
//用于数据接收和发送
m_pArchiveIn = new CArchive(m_pFile,CArchive::load);
m_pArchiveOut = new CArchive(m_pFile,CArchive::store);
//将用户名发送给服务器
SendMsg(m_strNcom, SENDING_NICKNAME, false);
枫叶文学网www.fywxw.com
第11 章 网络编程
·317·
CString strTemp;
strTemp.Format("进入聊天室");
//作为普通消息发送给服务器
SendMsg(strTemp, NORMAL_MESSAGE, true);
return TRUE;
}
为SendMsg()函数编写如下代码:
void CChatClientDoc::SendMsg(CString& strText, int mCode, BOOL bSendHandle)
{
if (m_pArchiveOut != NULL)
{
CMsg msg;
msg.code = mCode;
msg.m_strText = (bSendHandle ? m_strNcom + _T(": ") + strText : strText);
TRY
{
msg.Serialize(*m_pArchiveOut);
m_pArchiveOut->Flush();
}
CATCH(CFileException, e)
{
m_pArchiveOut->Abort();
delete m_pArchiveOut;
m_pArchiveOut = NULL;
CString strTemp;
strTemp.Format("发送失败");
DisplayMsg(strTemp);
}
END_CATCH
}
}
为ProcessReceive()函数编写如下代码:
void CChatClientDoc::ProcessReceive()
{
do
{
ReceiveMsg();
if (m_pSocket == NULL)
return;
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·318·
}
while(!m_pArchiveIn->IsBufferEmpty());
}
为ReceiveMsg()函数编写如下代码:
void CChatClientDoc::ReceiveMsg()
{
CMsg msg;
TRY
{
msg.Serialize(*m_pArchiveIn);
if(msg.code == SENDING_CHATTERS_LIST)
{
//更新用户列表
UpdateChattersList(&msg);
return;
}
if(msg.code == USED_NAME)
{
//如果是用户名已存在信息则关闭连接,退出
AfxMessageBox(msg.m_strText);
msg.m_bClose = TRUE;
OnDisconnect();
return;
}
//显示消息
DisplayMsg(msg.m_strText);
}
CATCH(CFileException, e)
{
msg.m_bClose = TRUE;
m_pArchiveOut->Abort();
CString strTemp;
strTemp.Format("接收数据失败");
DisplayMsg(strTemp);
}
END_CATCH
//如果连接已关闭则删除各对象
if (msg.m_bClose)
{
delete m_pArchiveIn;
枫叶文学网www.fywxw.com
第11 章 网络编程
·319·
m_pArchiveIn = NULL;
delete m_pArchiveOut;
m_pArchiveOut = NULL;
delete m_pFile;
m_pFile = NULL;
delete m_pSocket;
m_pSocket = NULL;
}
}
为DisplayMsg()函数编写如下代码:
void CChatClientDoc::DisplayMsg(LPCTSTR lpszText)
{
for(POSITION pos=GetFirstViewPosition();pos!=NULL;)
{
CView* pView = GetNextView(pos);
CMessageView* pChatView = DYNAMIC_DOWNCAST(CMessageView, pView);
if (pChatView != NULL)
pChatView->ShowMessage(lpszText);
}
}
为UpdateChattersList()函数编写如下代码:
void CChatClientDoc::UpdateChattersList(CMsg* pMsg)
{
CChattersView* pChattersView;
for(POSITION pos=GetFirstViewPosition();pos!=NULL;)
{
CView* pView = GetNextView(pos);
pChattersView = DYNAMIC_DOWNCAST(CChattersView, pView);
//首先清空用户列表视图
if (pChattersView != NULL)
pChattersView->ClearChattersList();
}
CString strTemp = pMsg->m_strText;
//得到所有的用户名并加入到用户列表中
do
{
CString sNcom = strTemp.Left(strTemp.Find(":",0));
pChattersView->AddToChattersList(sNcom);
strTemp = strTemp.Mid(strTemp.Find(":" , 0)+1);
}while(strTemp.Find(":",0) != -1);
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·320·
}
为DeleteContents()函数编写如下代码:
void CChatClientDoc::DeleteContents()
{
if ((m_pSocket != NULL) && (m_pFile != NULL) && (m_pArchiveOut != NULL))
{
//首先发送用户名
SendMsg(m_strNcom, LEAVING_CHAT, false);
CMsg msg;
CString strTemp;
//发送普通消息
strTemp.Format(":离开了聊天室");
msg.code = NORMAL_MESSAGE;
msg.m_bClose = TRUE;
msg.m_strText = m_strNcom + strTemp;
msg.Serialize(*m_pArchiveOut);
m_pArchiveOut->Flush();
}
//删除各对象
delete m_pArchiveOut;
m_pArchiveOut = NULL;
delete m_pArchiveIn;
m_pArchiveIn = NULL;
delete m_pFile;
m_pFile = NULL;
//关闭连接
if (m_pSocket != NULL)
{
m_pSocket->ShutDown(2);
delete m_pSocket;
m_pSocket = NULL;
}
//更新视图
for(POSITION pos=GetFirstViewPosition();pos!=NULL;)
{
CView* pView = GetNextView(pos);
if (pView->IsKindOf(RUNTIME_CLASS(CMessageView)))
{
CMessageView* pChatView = (CMessageView*)pView;
pChatView->GetEditCtrl().SetWindowText(_T(""));
枫叶文学网www.fywxw.com
第11 章 网络编程
·321·
}
if (pView->IsKindOf(RUNTIME_CLASS(CChattersView)))
{
CChattersView* pCChattersView = (CChattersView*)pView;
pCChattersView->ClearChattersList();
}
}
CDoccomnt::DeleteContents();
}
至此,整个程序编写完毕。分别运行服务器端程序和客户端程序,效果如图11-13~图11-15
所示。
图11-13 服务器端界面 图11-14 客户端界面1
图11-15 客户端界面2
本程序实现了一个简单的基于服务器/客户端模型的网络聊天系统,系统功能虽然简单,
但是体现了一般网络编程的基本步骤。在本程序中,由于对信息进行了封装,且采用了文档-
视图结构,用户可以很容易扩展其功能,比如可以加入两人私聊(其他人看不到聊天内容)、
服务器广播等功能。由于篇幅所限,这些功能请读者自行实现。
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·322·
11.5 利用 MSComm 控件进行串口编程
计算机串口编程在网络通信中也有着十分广泛的应用,比如电话、传真、视频控制等。
本节将介绍如何在Visual C++中利用MSComm 控件进行串口编程。
11.5.1 MSComm 控件介绍
1.MSComm 控件处理通信的方式
MSComm 控件为应用程序提供了读写串口功能,它提供了两种处理通信的方法。
? 事件驱动方式。在这种情况下,使用MSComm 控件的OnComm 事件可以捕获和处理
这些通信事件。同时,OnComm 也可以捕获和处理通信中的错误。
? 查询方式。用户可以在每个重要的程序功能之后检查CommEvent 属xìng的值来检测事
件和通信错误。在通信频繁的情况下,这种方式更为方便。
2.MSComm 控件常用属xìng
(1)CommPort 属xìng
该属xìng用于设置或返回通信端口号,端口号的范围是1~16,默认为1。对应的函数为
void SetCommPort(short nNewValue)和short GetCommPort()。
(2)Settings 属xìng
该属xìng用于设置或返回数据传输率、奇偶校验、数据位和停止位参数,其属xìng值格式为
“BBBB,P,D,S”。
其中BBBB 为数据传输率,P 为奇偶校验,D 为数据位,S 为停止位。默认值为
“9600,N,8,1”。
该属xìng对应的函数为void SetSettings(LPCTSTR lpszNewValue)和String GetSettings()。
(3)PortOpen 属xìng
该属xìng用于设置或返回串口状态,值为TRUE 时打开,值为FALSE 时关闭。如果要打
开端口,则必须现设置CommPort 属xìng。
该属xìng对应的函数为void SetPortOpen(BOOL bNewValue)和BOOL GetPortOpen()。
(4)Input 属xìng
该属xìng用于从接收缓冲区中读取数据,其对应的函数为VARIANT GetInput()。
(5)InputMode 属xìng
该属xìng用于设置或返回从接收缓冲区读取数据的格式,属xìng值为0 时表示以文本格式读
取数据;属xìng之为1 时表示以二进制格式读取数据;属xìng值为2 时表示以十六进制格式读取
数据。
该属xìng对应的函数分别为void SetInputMode(long nNewValue)和long GetInputMode()。
(6
松语文学免费小说阅读_www.16sy.com
成员函数 说明
BOOL ConnectSocket(LPCTSTR lpszHandle,
LPCTSTR lpszAddress, int nPort)
连接服务器,3 个参数依次是用户名、服务器地址
和端口号
枫叶文学网www.fywxw.com
第11 章 网络编程
·315·
续表
成员函数 说明
void ProcessReceive() 当接收到信息时调用此函数,进行信息接收等cāo作
void SendMsg(CString& strText, int mCode, BOOL
bSendNcom)
发送信息,3 个参数分别表示信息内容、信息种类
和是否发送用户名
void ReceiveMsg() 接收信息
void DisplayMsg(LPCTSTR lpszText) 显示信息
void UpdateChattersList(CMsg* pMsg) 更新用户列表
virtual void DeleteContents() 断开时所作的工作
下面开始为各函数编写代码。
首先在构造函数中将各成员变量初始化,代码如下:
CChatClientDoc::CChatClientDoc()
{
// TODO: add one-tcom construction code here
bIsConnected = FALSE;
m_pSocket = NULL;
m_pFile = NULL;
m_pArchiveOut = NULL;
m_pArchiveIn = NULL;
}
接着为“连接”菜单项编写响应函数,代码如下:
void CChatClientDoc::OnConnect()
{
// TODO: Add your command handler code here
CLogDlg dlg;
if(dlg.DoModal() == IDOK)
{
if(ConnectSocket(dlg.m_Ncom, dlg.m_Server, dlg.m_Port))
bIsConnected = TRUE;
else
AfxMessageBox("连接服务器失败!");
}
}
当连接后,应该使“连接”菜单项无效,为消息UPDATA_COMMAND_UI 添加响应函
数如下:
void CChatClientDoc::OnUpdateConnect(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->Enable(!bIsConnected);
}
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·316·
为“断开”菜单项添加响应函数,代码如下:
void CChatClientDoc::OnDisconnect()
{
// TODO: Add your command handler code here
DeleteContents();
bIsConnected = FALSE;
}
当断开后,应当使“断开”菜单项无效,为消息UPDATA_COMMAND_UI 添加如下响
应函数:
void CChatClientDoc::OnUpdateDisconnect(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->Enable(bIsConnected);
}
为ConnectSocket()函数编写如下代码:
BOOL CChatClientDoc::ConnectSocket(LPCTSTR lpszHandle, LPCTSTR lpszAddress, int nPort)
{
m_strNcom = lpszHandle;
m_pSocket = new CChatSocket(this);
//创建socket 失败
if (!m_pSocket->Create())
{
delete m_pSocket;
m_pSocket = NULL;
AfxMessageBox("创建socket 失败!");
return FALSE;
}
//连接失败
if(!m_pSocket->Connect(lpszAddress, nPort))
{
delete m_pSocket;
m_pSocket = NULL;
return FALSE;
}
m_pFile = new CSocketFile(m_pSocket);
//用于数据接收和发送
m_pArchiveIn = new CArchive(m_pFile,CArchive::load);
m_pArchiveOut = new CArchive(m_pFile,CArchive::store);
//将用户名发送给服务器
SendMsg(m_strNcom, SENDING_NICKNAME, false);
枫叶文学网www.fywxw.com
第11 章 网络编程
·317·
CString strTemp;
strTemp.Format("进入聊天室");
//作为普通消息发送给服务器
SendMsg(strTemp, NORMAL_MESSAGE, true);
return TRUE;
}
为SendMsg()函数编写如下代码:
void CChatClientDoc::SendMsg(CString& strText, int mCode, BOOL bSendHandle)
{
if (m_pArchiveOut != NULL)
{
CMsg msg;
msg.code = mCode;
msg.m_strText = (bSendHandle ? m_strNcom + _T(": ") + strText : strText);
TRY
{
msg.Serialize(*m_pArchiveOut);
m_pArchiveOut->Flush();
}
CATCH(CFileException, e)
{
m_pArchiveOut->Abort();
delete m_pArchiveOut;
m_pArchiveOut = NULL;
CString strTemp;
strTemp.Format("发送失败");
DisplayMsg(strTemp);
}
END_CATCH
}
}
为ProcessReceive()函数编写如下代码:
void CChatClientDoc::ProcessReceive()
{
do
{
ReceiveMsg();
if (m_pSocket == NULL)
return;
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·318·
}
while(!m_pArchiveIn->IsBufferEmpty());
}
为ReceiveMsg()函数编写如下代码:
void CChatClientDoc::ReceiveMsg()
{
CMsg msg;
TRY
{
msg.Serialize(*m_pArchiveIn);
if(msg.code == SENDING_CHATTERS_LIST)
{
//更新用户列表
UpdateChattersList(&msg);
return;
}
if(msg.code == USED_NAME)
{
//如果是用户名已存在信息则关闭连接,退出
AfxMessageBox(msg.m_strText);
msg.m_bClose = TRUE;
OnDisconnect();
return;
}
//显示消息
DisplayMsg(msg.m_strText);
}
CATCH(CFileException, e)
{
msg.m_bClose = TRUE;
m_pArchiveOut->Abort();
CString strTemp;
strTemp.Format("接收数据失败");
DisplayMsg(strTemp);
}
END_CATCH
//如果连接已关闭则删除各对象
if (msg.m_bClose)
{
delete m_pArchiveIn;
枫叶文学网www.fywxw.com
第11 章 网络编程
·319·
m_pArchiveIn = NULL;
delete m_pArchiveOut;
m_pArchiveOut = NULL;
delete m_pFile;
m_pFile = NULL;
delete m_pSocket;
m_pSocket = NULL;
}
}
为DisplayMsg()函数编写如下代码:
void CChatClientDoc::DisplayMsg(LPCTSTR lpszText)
{
for(POSITION pos=GetFirstViewPosition();pos!=NULL;)
{
CView* pView = GetNextView(pos);
CMessageView* pChatView = DYNAMIC_DOWNCAST(CMessageView, pView);
if (pChatView != NULL)
pChatView->ShowMessage(lpszText);
}
}
为UpdateChattersList()函数编写如下代码:
void CChatClientDoc::UpdateChattersList(CMsg* pMsg)
{
CChattersView* pChattersView;
for(POSITION pos=GetFirstViewPosition();pos!=NULL;)
{
CView* pView = GetNextView(pos);
pChattersView = DYNAMIC_DOWNCAST(CChattersView, pView);
//首先清空用户列表视图
if (pChattersView != NULL)
pChattersView->ClearChattersList();
}
CString strTemp = pMsg->m_strText;
//得到所有的用户名并加入到用户列表中
do
{
CString sNcom = strTemp.Left(strTemp.Find(":",0));
pChattersView->AddToChattersList(sNcom);
strTemp = strTemp.Mid(strTemp.Find(":" , 0)+1);
}while(strTemp.Find(":",0) != -1);
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·320·
}
为DeleteContents()函数编写如下代码:
void CChatClientDoc::DeleteContents()
{
if ((m_pSocket != NULL) && (m_pFile != NULL) && (m_pArchiveOut != NULL))
{
//首先发送用户名
SendMsg(m_strNcom, LEAVING_CHAT, false);
CMsg msg;
CString strTemp;
//发送普通消息
strTemp.Format(":离开了聊天室");
msg.code = NORMAL_MESSAGE;
msg.m_bClose = TRUE;
msg.m_strText = m_strNcom + strTemp;
msg.Serialize(*m_pArchiveOut);
m_pArchiveOut->Flush();
}
//删除各对象
delete m_pArchiveOut;
m_pArchiveOut = NULL;
delete m_pArchiveIn;
m_pArchiveIn = NULL;
delete m_pFile;
m_pFile = NULL;
//关闭连接
if (m_pSocket != NULL)
{
m_pSocket->ShutDown(2);
delete m_pSocket;
m_pSocket = NULL;
}
//更新视图
for(POSITION pos=GetFirstViewPosition();pos!=NULL;)
{
CView* pView = GetNextView(pos);
if (pView->IsKindOf(RUNTIME_CLASS(CMessageView)))
{
CMessageView* pChatView = (CMessageView*)pView;
pChatView->GetEditCtrl().SetWindowText(_T(""));
枫叶文学网www.fywxw.com
第11 章 网络编程
·321·
}
if (pView->IsKindOf(RUNTIME_CLASS(CChattersView)))
{
CChattersView* pCChattersView = (CChattersView*)pView;
pCChattersView->ClearChattersList();
}
}
CDoccomnt::DeleteContents();
}
至此,整个程序编写完毕。分别运行服务器端程序和客户端程序,效果如图11-13~图11-15
所示。
图11-13 服务器端界面 图11-14 客户端界面1
图11-15 客户端界面2
本程序实现了一个简单的基于服务器/客户端模型的网络聊天系统,系统功能虽然简单,
但是体现了一般网络编程的基本步骤。在本程序中,由于对信息进行了封装,且采用了文档-
视图结构,用户可以很容易扩展其功能,比如可以加入两人私聊(其他人看不到聊天内容)、
服务器广播等功能。由于篇幅所限,这些功能请读者自行实现。
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·322·
11.5 利用 MSComm 控件进行串口编程
计算机串口编程在网络通信中也有着十分广泛的应用,比如电话、传真、视频控制等。
本节将介绍如何在Visual C++中利用MSComm 控件进行串口编程。
11.5.1 MSComm 控件介绍
1.MSComm 控件处理通信的方式
MSComm 控件为应用程序提供了读写串口功能,它提供了两种处理通信的方法。
? 事件驱动方式。在这种情况下,使用MSComm 控件的OnComm 事件可以捕获和处理
这些通信事件。同时,OnComm 也可以捕获和处理通信中的错误。
? 查询方式。用户可以在每个重要的程序功能之后检查CommEvent 属xìng的值来检测事
件和通信错误。在通信频繁的情况下,这种方式更为方便。
2.MSComm 控件常用属xìng
(1)CommPort 属xìng
该属xìng用于设置或返回通信端口号,端口号的范围是1~16,默认为1。对应的函数为
void SetCommPort(short nNewValue)和short GetCommPort()。
(2)Settings 属xìng
该属xìng用于设置或返回数据传输率、奇偶校验、数据位和停止位参数,其属xìng值格式为
“BBBB,P,D,S”。
其中BBBB 为数据传输率,P 为奇偶校验,D 为数据位,S 为停止位。默认值为
“9600,N,8,1”。
该属xìng对应的函数为void SetSettings(LPCTSTR lpszNewValue)和String GetSettings()。
(3)PortOpen 属xìng
该属xìng用于设置或返回串口状态,值为TRUE 时打开,值为FALSE 时关闭。如果要打
开端口,则必须现设置CommPort 属xìng。
该属xìng对应的函数为void SetPortOpen(BOOL bNewValue)和BOOL GetPortOpen()。
(4)Input 属xìng
该属xìng用于从接收缓冲区中读取数据,其对应的函数为VARIANT GetInput()。
(5)InputMode 属xìng
该属xìng用于设置或返回从接收缓冲区读取数据的格式,属xìng值为0 时表示以文本格式读
取数据;属xìng之为1 时表示以二进制格式读取数据;属xìng值为2 时表示以十六进制格式读取
数据。
该属xìng对应的函数分别为void SetInputMode(long nNewValue)和long GetInputMode()。
(6
松语文学免费小说阅读_www.16sy.com