目录
(1)、重写CSocket虚函数OnReceive,并且传入对话框的指针
(8)、接收到数据的处理函数ProcessPendingRead
3)、初始化发送消息的EDIT只读,服务端IP和PORT可以修改
6)、重写框架类的关闭窗口函数,实现关闭窗口之后调用离开房间按钮事件。
1、UI的设计:
2、代码的实现:
首先自定义一个类继承与CSocket类
(1)、重写CSocket虚函数OnReceive,并且传入对话框的指针
声明对话框类
class CUdpClientDlg;
传递指针
CClientSocket(CUdpClientDlg * pdlg);
CUdpClientDlg *m_pMainDlg;
CClientSocket::CClientSocket(CUdpClientDlg * pdlg)
{
m_pMainDlg = pdlg;
}
重写OnReceive函数实现底层的通信,并且自定义一个处理函数ProcessPendingRead
void CClientSocket::OnReceive(int nErrorCode)
{
// TODO: 在此添加专用代码和/或调用基类
CSocket::OnReceive(nErrorCode);
m_pMainDlg->ProcessPendingRead();
}
(2)、初始化SOCKET
//初始化SOCKET
m_pClientSocket = new CClientSocket(this);
m_pClientSocket->Create(0, SOCK_DGRAM);//使用数据报类型
(3)、绑定本地IP和端口
//绑定了本地IP和端口
CString strIP;
UINT uiPort;
m_pClientSocket->GetSockName(strIP, uiPort);
(4)、显示本地IP和端口在界面
SetDlgItemText(IDC_EDIT_LOAD_IP, strIP);
SetDlgItemInt(IDC_EDIT_LOAD_PORT, uiPort);
(5)、进入房间事件
获取服务端IP和端口
CString strIp;
UINT uiPort;
GetDlgItemTextW(IDC_EDIT_SERVER_IP, strIp);
uiPort = GetDlgItemInt(IDC_EDIT_SERVER_PORT);
进入房间发送enter
CString strEnterMsg("enter");
int nSead = m_pClientSocket->SendTo(strEnterMsg, strEnterMsg.GetLength() + 100, uiPort, strIp);
if (nSead == SOCKET_ERROR)
{
MessageBox(L"进入聊天室失败!");
return;
}
设置标志位
//设置标志位
m_EnterRoom = true;
(6)、离开房间事件
首先获取服务端IP和地址
CString strIp;
UINT uiPort;
GetDlgItemTextW(IDC_EDIT_SERVER_IP, strIp);
uiPort = GetDlgItemInt(IDC_EDIT_SERVER_PORT);
离开房间发送leave
CString strEnterMsg("leave");
int nSead = m_pClientSocket->SendTo(strEnterMsg, strEnterMsg.GetLength() + 100, uiPort, strIp);
if (nSead == SOCKET_ERROR)
{
MessageBox(L"离开聊天室失败!");
return;
}
设置标志位
m_bEnterRoom = true;
(7)、发送信息事件
获取服务端的地址
//获取服务端的地址
CString strIp;
UINT uiPort;
GetDlgItemTextW(IDC_EDIT_SERVER_IP, strIp);
uiPort = GetDlgItemInt(IDC_EDIT_SERVER_PORT);
发送数据
//发送数据
CString strMsg;
GetDlgItemText(IDC_EDIT_SEND_MESSAGE, strMsg);
m_pClientSocket->SendTo(strMsg, strMsg.GetLength() + 100, uiPort, strIp);
清空发送文本框
//清空
SetDlgItemText(IDC_EDIT_SEND_MESSAGE, L"");
(8)、接收到数据的处理函数ProcessPendingRead
CHAR buffer[4096];
int nRead = m_pClientSocket->ReceiveFrom(buffer, 4096,NULL,NULL);
if (nRead == SOCKET_ERROR)
{
return;
}
buffer[nRead] = L'\0';//字符串\0结尾所以要加上
CString strMsg(buffer);
CString alMsg;
GetDlgItemText(IDC_EDIT_CHAT_MESSAGE, alMsg);
SetDlgItemText(IDC_EDIT_CHAT_MESSAGE, alMsg + L"\r\n" + strMsg);
(9)、优化处理
1)、初始化默认服务端的端口和IP在框架的入口函数
//设置服务端默认的端口和IP
SetDlgItemText(IDC_EDIT_SERVER_IP, L"127.0.0.1");
SetDlgItemText(IDC_EDIT_SERVER_PORT, L"8080");
2)、没有加入房间,发送按钮和退出按钮都不能点击
//设置按钮初始化状态
GetDlgItem(IDC_BUTTON_OUT)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(FALSE);
3)、初始化发送消息的EDIT只读,服务端IP和PORT可以修改
GetDlgItem(IDC_EDIT_SEND_MESSAGE)->EnableWindow(FALSE);
GetDlgItem(IDC_EDIT_SERVER_IP)->EnableWindow(TRUE);
GetDlgItem(IDC_EDIT_SERVER_PORT)->EnableWindow(TRUE);
4)、加入房间之后重新设置按钮的状态
//设置按钮文本框的状态
//设置按钮初始化状态
GetDlgItem(IDC_BUTTON_OUT)->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(TRUE);
((CEdit*)GetDlgItem(IDC_EDIT_SEND_MESSAGE))->SetReadOnly(FALSE);
((CEdit*)GetDlgItem(IDC_EDIT_SERVER_IP))->SetReadOnly(TRUE);
((CEdit*)GetDlgItem(IDC_EDIT_SERVER_PORT))->SetReadOnly(TRUE);
5)、离开房间重新设置按钮的状态
GetDlgItem(IDC_BUTTON_OUT)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(FALSE);
((CEdit*)GetDlgItem(IDC_EDIT_SEND_MESSAGE))->SetReadOnly(TRUE);
((CEdit*)GetDlgItem(IDC_EDIT_SERVER_IP))->SetReadOnly(FALSE);
((CEdit*)GetDlgItem(IDC_EDIT_SERVER_PORT))->SetReadOnly(FALSE);
6)、重写框架类的关闭窗口函数,实现关闭窗口之后调用离开房间按钮事件。
BOOL CUdpClientDlg::DestroyWindow()
{
// TODO: 在此添加专用代码和/或调用基类
if (m_bEnterRoom)
{
OnBnClickedButtonOut();
}
return CDialogEx::DestroyWindow();
}
3、最终的UI:
实现UDP连接服务端