目录
1、客户端创建流程:
2、UI设计:
3、代码实现:
(1)、ConnectSocket中重写OnReceive函数接收信息
(2)、框架类入口函数初始化
(3)、加入房间功能实现
(4)、离开房间功能实现
(5)、发送消息功能实现
(6)、OnPendingRead函数实现
4、最终运行结果:
1、客户端创建流程:
(1)、创建一个Socket对象并且自动绑定一个端口。
(2)、调用Connect()函数,建立一个到服务端的连接。
(3)、发送一个特殊消息进入房间enter。
(4)、使用Receive()函数,Send函数收发数据。
(5)、发送一个特殊消息退出房间leave。
2、UI设计:
3、代码实现:
(1)、ConnectSocket中重写OnReceive函数接收信息
CConnectSocket(CTcpClientDlg *pdlg);//框架类的指针,目的处理函数得放在框架中
~CConnectSocket();
CTcpClientDlg * m_pMainDlg;
virtual void OnReceive(int nErrorCode);
void CConnectSocket::OnReceive(int nErrorCode)
{
// TODO: 在此添加专用代码和/或调用基类CSocket::OnReceive(nErrorCode);
m_pMainDlg->OnPendingRead();//处理函数在框架中,因为显示在对话框中
}
(2)、框架类入口函数初始化
//初始化服务端的IP,Port放在显示在UI
SetDlgItemText(IDC_EDIT_SERVER_IP, L"127.0.0.1");
SetDlgItemText(IDC_EDIT_SERVER_PORT, L"8080");//设置各个按钮控件的状态
GetDlgItem(IDC_BUTTON_ENTER_ROOM)->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON_LEAVE_ROOM)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(FALSE);//设置EDIT控件的只读或者可写
((CEdit*)GetDlgItem(IDC_EDIT_SEND_MESSAGE))->SetReadOnly(TRUE);
((CEdit*)GetDlgItem(IDC_EDIT_SERVER_PORT))->SetReadOnly(TRUE);
((CEdit*)GetDlgItem(IDC_EDIT_SERVER_IP))->SetReadOnly(TRUE);
(3)、加入房间功能实现
随机分配一个空闲的端口号
// 创建tcp套接字并且绑定一个自动分配的端口号
m_Pconnect = new CConnectSocket(this);
m_Pconnect->Create();
把本地的IP和Port显示在UI
//获取本地的端口和IP,并显示在UI
CString strlocalIP;
UINT uilocalPort;
m_Pconnect->GetSockName(strlocalIP, uilocalPort);
SetDlgItemText(IDC_EDIT_LOCAL_IP, strlocalIP);
SetDlgItemInt(IDC_EDIT_LOCAL_PORT, uilocalPort);
补充:建立TCP通讯的条件:
服务端和客户端的俩个端口得是空闲端口,客户端指定发送信息的IP地址,客户端在指定的IP上等待连接,同时还得有TCP\IP协议。
调用Connect连接服务端和客户端
//调用connect函数连接服务端
CString strServerIP;
UINT uiServerPort;//服务端的IP和Port
GetDlgItemText(IDC_EDIT_SERVER_IP, strServerIP);
uiServerPort = GetDlgItemInt(IDC_EDIT_SERVER_PORT);if (!m_Pconnect->Connect(strServerIP, uiServerPort))
{
MessageBox(L"连接服务端失败");
return;
}
连接成功说明一个客户端加入房间
CString strEnterRoom = L"enter";
m_Pconnect->Send(strEnterRoom, strEnterRoom.GetLength() + 100);
m_bEnterRoom = TRUE;
界面的改变
GetDlgItem(IDC_BUTTON_ENTER_ROOM)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_LEAVE_ROOM)->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(TRUE);((CEdit*)GetDlgItem(IDC_EDIT_SEND_MESSAGE))->SetReadOnly(FALSE);
(4)、离开房间功能实现
CString strleaveRoom = L"leave";
m_Pconnect->Send(strleaveRoom, strleaveRoom.GetLength() + 100);
m_bEnterRoom = FALSE;GetDlgItem(IDC_BUTTON_ENTER_ROOM)->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON_LEAVE_ROOM)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(FALSE);((CEdit*)GetDlgItem(IDC_EDIT_SEND_MESSAGE))->SetReadOnly(TRUE);
((CEdit*)GetDlgItem(IDC_EDIT_SERVER_PORT))->SetReadOnly(FALSE);
((CEdit*)GetDlgItem(IDC_EDIT_SERVER_IP))->SetReadOnly(FALSE);
(5)、发送消息功能实现
发送消息给客户端
// TODO: 在此添加控件通知处理程序代码
CString strMsg;
GetDlgItemText(IDC_EDIT_SEND_MESSAGE, strMsg);
m_Pconnect->Send(strMsg, strMsg.GetLength() + 100);SetDlgItemText(IDC_EDIT_SEND_MESSAGE, L"");//将文本框清空方便下次输入
(6)、OnPendingRead函数实现
接收从客户端分发的消息
TCHAR buff[4096];
int nRead =m_Pconnect->Receive(buff, 4096);
if (nRead == SOCKET_ERROR)
{
return;
}
buff[nRead] = L'\0';
CString charMsg(buff);CString alMsg;
GetDlgItemText(IDC_EDIT_CHAT_MESSAGE, alMsg);
SetDlgItemText(IDC_EDIT_CHAT_MESSAGE, alMsg + L"\r\n" + charMsg);