mfc基于socket的多线程聊天程序
时间: 2023-08-02 09:13:50 浏览: 134
MFC(Microsoft Foundation Class)是微软公司提供的面向对象的 C++ 库,用于 Windows 程序的开发。基于 MFC 的多线程聊天程序可以使用 socket 技术实现。
以下是实现步骤:
1. 创建一个 MFC 应用程序,选择“多文档视图”类型。
2. 在应用程序类中添加两个变量:`CAsyncSocket m_server;` 和 `CPtrList m_socketList;`。`m_server` 用于监听客户端连接,`m_socketList` 用于存储连接的客户端 socket。
3. 在应用程序类的 InitInstance 函数中创建 socket:
```
if(!m_server.Create(8888)){
AfxMessageBox(_T("Failed to create server socket"));
return FALSE;
}
if(!m_server.Listen()){
AfxMessageBox(_T("Failed to listen on server socket"));
return FALSE;
}
```
4. 在应用程序类中添加一个成员函数 `OnAccept`,当有客户端连接时,该函数将被调用。在该函数中创建客户端 socket,并将其加入到 `m_socketList` 中。
```
void CMyChatApp::OnAccept(){
CMySocket* pSocket = new CMySocket();
if(m_server.Accept(*pSocket)){
m_socketList.AddTail(pSocket);
pSocket->AsyncSelect(FD_CLOSE | FD_READ);
}else{
delete pSocket;
}
}
```
5. 创建一个自定义 socket 类 `CMySocket`,继承自 `CAsyncSocket`。在该类中添加一个成员函数 `OnClose`,当客户端断开连接时,该函数将被调用。在该函数中将客户端 socket 从 `m_socketList` 中删除。
```
void CMySocket::OnClose(int nErrorCode){
POSITION pos = theApp.m_socketList.Find(this);
if(pos){
theApp.m_socketList.RemoveAt(pos);
}
delete this;
}
```
6. 在 `CMySocket` 类中添加一个成员函数 `OnReceive`,当有数据传入时,该函数将被调用。在该函数中读取数据并将其广播给所有连接的客户端。
```
void CMySocket::OnReceive(int nErrorCode){
char buf[1024];
int len = Receive(buf, sizeof(buf));
if(len > 0){
buf[len] = '\0';
POSITION pos = theApp.m_socketList.GetHeadPosition();
while(pos){
CMySocket* pSocket = (CMySocket*)theApp.m_socketList.GetNext(pos);
if(pSocket != this){
pSocket->Send(buf, len);
}
}
}
}
```
7. 在主窗口中添加一个编辑框和一个按钮。在按钮的 Click 事件中创建一个客户端 socket,并连接到服务器。
```
void CMyChatView::OnButtonConnect(){
CMySocket* pSocket = new CMySocket();
if(pSocket->Create()){
if(pSocket->Connect(_T("127.0.0.1"), 8888)){
pSocket->AsyncSelect(FD_CLOSE | FD_READ);
theApp.m_socketList.AddTail(pSocket);
}else{
delete pSocket;
}
}else{
delete pSocket;
}
}
```
8. 在主窗口的 `OnDraw` 函数中添加一个定时器,每隔一段时间检查是否有新的客户端连接。在该函数中添加以下代码:
```
if(m_timer == 0){
m_timer = SetTimer(1, 1000, NULL);
}
```
9. 在主窗口类中添加一个成员变量 `UINT_PTR m_timer;`。
10. 实现定时器事件 `OnTimer`,在该事件中调用应用程序类的 `OnAccept` 函数检查是否有新的客户端连接。
```
void CMyChatView::OnTimer(UINT_PTR nIDEvent){
if(nIDEvent == 1){
theApp.OnAccept();
}
}
```
11. 在主窗口中添加一个成员函数 `OnSocketNotify`,当有数据传入时,该函数将被调用。在该函数中读取数据并显示在编辑框中。
```
void CMyChatView::OnSocketNotify(WPARAM wParam, LPARAM lParam){
CMySocket* pSocket = (CMySocket*)wParam;
char buf[1024];
int len = pSocket->Receive(buf, sizeof(buf));
if(len > 0){
buf[len] = '\0';
CString strText;
m_edit.GetWindowText(strText);
strText += buf;
m_edit.SetWindowText(strText);
m_edit.LineScroll(m_edit.GetLineCount() - 1);
}
}
```
12. 在主窗口类中添加一个成员变量 `HWND m_hWndServer;`。
13. 在主窗口的 Create 函数中创建一个隐藏的窗口,并将其消息处理函数设置为 `OnSocketNotify`。在该函数中添加以下代码:
```
m_hWndServer = CreateWindowEx(0, AfxRegisterWndClass(0), _T(""), 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, AfxGetInstanceHandle(), NULL);
::SetWindowLong(m_hWndServer, GWL_USERDATA, (LONG)this);
```
14. 在主窗口的 `OnClose` 函数中删除隐藏窗口。
```
void CMyChatView::OnClose(){
::DestroyWindow(m_hWndServer);
CFormView::OnClose();
}
```
15. 在主窗口的 `OnSize` 函数中调整编辑框的大小。
```
void CMyChatView::OnSize(UINT nType, int cx, int cy){
CFormView::OnSize(nType, cx, cy);
m_edit.MoveWindow(0, 0, cx, cy - 50);
m_button.MoveWindow(cx - 100, cy - 50, 100, 50);
}
```
16. 在主窗口类中添加一个成员函数 `PostSocketNotify`,用于向隐藏窗口发送消息。在该函数中添加以下代码:
```
::PostMessage(m_hWndServer, WM_SOCKET_NOTIFY, (WPARAM)pSocket, 0);
```
17. 在主窗口类中添加一个宏定义 `WM_SOCKET_NOTIFY`。
```
#define WM_SOCKET_NOTIFY (WM_USER + 1)
```
18. 在隐藏窗口的消息处理函数 `OnSocketNotify` 中调用主窗口的 `OnSocketNotify` 函数。
```
LRESULT CALLBACK CMyChatView::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
switch(message){
case WM_SOCKET_NOTIFY:
{
CMyChatView* pView = (CMyChatView*)::GetWindowLong(hWnd, GWL_USERDATA);
pView->OnSocketNotify(wParam, lParam);
break;
}
}
return CFormView::WndProc(hWnd, message, wParam, lParam);
}
```
至此,基于 MFC 和 socket 的多线程聊天程序就完成了。
阅读全文