• 沒有找到結果。

前面介绍了 MFC Socket 的基本开发技术,本节将基于 Visual C++,利用 MFC 实现一个简单 的网络聊天室的开发。为了便于理解,这里只实现基本功能,即客户将聊天信息发送至服务器,而 服务器将收到的信息分发给所有的客户,从而使各客户均能看得其他用户的聊天信息。在此基础上,

读者可进行其他扩展开发。

5.4.1 服务器端程序的开发

服务器实现的基本功能是开启服务端口,等待客户的连接。当有客户连接后,接收客户发送的 文本信息,并将该信息转发给所有与之连接的客户。

基本实现过程为从 CSocket 类派生两个 Socket 类:CListenSocket,用于创建监听 Socket;

CCommSocket , 用 于 创 建 通 信 Socket 。 创 建 一 个 CCommSocketList 类 , 用 于 记 录 所 有 的 CCommSocket 对象。在 CListenSocket 类中,重载 OnAccept 函数,实现创建 CCommSocket 对象与 客户 Socket 进行通信。具体开发过程如下:

(1)启动 Visual C++ 6.0,使用 AppWizard 创建一个基于对话框的 MFC 工程,工程名为

5

Chapter

ntChatRoomServer。在 MFC AppWizard Step 2 时,需要选中 Windows Sockets 复选项。

(2)以 CSocket 类为基类派生新类 CListenSocket,用于实现服务器端的监听套接字。在其中 重载 CSocket 类的 OnAccept()函数,收到连接请求后创建客户套接字,与客户端进行通信。实现代 码如下:

void CListenSocket::OnAccept(int nErrorCode) {

//TODO:在此添加需要的代码或者调用基类的实现

CClientSocket *tmp=new CClientSocket(&CCSL); //创建客户套接字

Accept(*tmp); //接收客户数据

CCSL.Add(tmp); //添加到客户套接字列表中

CSocket::OnAccept(nErrorCode);

}

(3)以 CSocket 类为基类派生新类 CCommSocket,用于创建客户 Socket 列表。重载 OnReceive() 函数,实现将服务器接收的信息分发给所有连接至服务器的 Socket。

CCommSocket 类的头文件实现如下:

class CCommSocketList;

class CCommSocket : public CSocket {

void CCommSocket::OnReceive(int nErrorCode) {

5 Chapter

while (tmp->Next) tmp=tmp->Next;

tmp->Next=add; //添加列表元素

return TRUE;

}

(5)启动服务和停止服务按钮响应函数的实现代码如下:

void CntChatRoomServerDlg::OnStart() //启动服务

{

//TODO:在此添加控制通知处理代码

GetDlgItem(IDC_START)->EnableWindow(false); //使“启动”按钮无效

m_ListenSocket.Create(4611); //创建监听套接字端口为 4611

void CntChatRoomServerDlg::OnStop() //停止服务

{

5

Chapter

实例的运行结果如图 5.8 所示。

图 5.8 服务器端的运行结果

5.4.2 客户端程序的开发

当客户端程序启动后,首先弹出“连接”对话框,通过指定的地址和用户名连接服务器。连接 成功后,客户就可以向服务器发信息,并接收服务器转发的信息。

基本的实现过程为创建 CSocket 类的派生类 CServerSocket,重载 OnReceive 函数。当客户连 接到服务器,服务器端有数据发送到本端时,将执行 OnReceive 函数,实现接收服务器 Socket 发 送的数据,并在窗口中显示。具体开发过程如下:

(1)启动 Visual C++ 6.0,使用 AppWizard 创建一个基于对话框的 MFC 工程,工程名为 ntChatRoomClient。在 MFC AppWizard Step 2 时,需要选中 Windows Sockets 复选项。

(2)以 CSocket 类为基类派生新类 CServerSocket,实现连接服务器、向服务器发送消息,并 从服务器接收信息的操作。

在 CServerSocket 类的头文件中声明相关成员变量和函数,如下:

class CntChatRoomClientDlg; //主对话框类

class CServerSocket : public CSocket {

//属性 public:

CntChatRoomClientDlg * myDlg; //主对话框指针

BOOL SetDlg(CntChatRoomClientDlg *tmp);

CString UserName; //用户名

SetDlg()函数实现在 Socket 对象中获取主对话框的指针,代码如下:

BOOL CServerSocket::SetDlg(CntChatRoomClientDlg *tmp) {

myDlg=tmp;

return true;

}

重载 CSocket 类的 OnReceive 函数,调用主对话框的成员函数 GetMessage,接收服务器的信 息,并添加到窗口的列表框中,代码如下:

void CServerSocket::OnReceive(int nErrorCode) {

//TODO:在此添加需要的代码或者调用基类的实现

myDlg->GetMessage(); //接收服务器信息

CSocket::OnReceive(nErrorCode);

}

主窗口类的 GetMessage()函数的实现代码如下:

BOOL CntChatRoomClientDlg::GetMessage()

5 Chapter

m_IDC_LIST_CHATBOX_CONTROL.AddString(buff); //添加到列表框 return true;

}

(3)在“连接”对话框的“连接”按钮响应函数 OnConnect()中,实现使用 CServerSocket 对 象连接服务器。当连接服务器成功后,如果服务器有发送到本端的数据,则会激发 FD_READ 事件,

调用 OnReceive 函数,读取数据,并显示在主窗口的列表框中。实现代码如下:

void CConnectedDlg::OnConnect() { sprintf(address,"%s",m_strAddress.GetBuffer(n));

address[n]=0;

myServerSocket->UserName=m_strUserName;

CDialog::OnOK(); //退出窗口 }

(4)在主窗口的“发送消息”按钮响应函数 OnButtonSend()中,实现使用 CServerSocket 对象 向服务器发送数据,实现代码如下:

void CntChatRoomClientDlg::OnButtonSend() {

int n;

char message[1000];

UpdateData(TRUE);

//在消息前添加用户名

m_IDC_EDIT_MESSAGE=myServerSocket->UserName+": "+m_IDC_EDIT_MESSAGE;

n=m_IDC_EDIT_MESSAGE.GetLength();

sprintf(message,"%s",m_IDC_EDIT_MESSAGE.GetBuffer(n));

message[n]=0;

相關文件