今天在学习了基于多线程的聊天室程序,另外还加上了socket编程。效果图如下
代码如下:
1、首先我们需要去加载套接字库,MFC中的函数 AfxSocketInit() 包装了函数 WSAStartup(), 在支持WinSock的应用程序的初始化函数IninInstance()中调用AfxSocketInit()进行初始化, 程序则不必调用WSACleanUp(). 需要的头文件是afxsock.h
BOOL CChartApp::InitInstance()
{
/*
...省略
*/
CWinApp::InitInstance();
if (!AfxSocketInit())
{
AfxMessageBox(_T("Failed to Initialize Sockets"), MB_OK | MB_ICONSTOP);
return FALSE;
}
/*
...省略
*/
}
2、ChartDlg.h
// ChartDlg.h : 头文件
//
#pragma once
#define WM_RECVDATA WM_USER + 1
struct RecvParam
{
SOCKET sock;
HWND hwnd;
};
// CChartDlg 对话框
class CChartDlg : public CDialog
{
// 构造
public:
CChartDlg(CWnd* pParent = NULL); // 标准构造函数
// 对话框数据
enum { IDD = IDD_CHART_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg LRESULT OnRecvData(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
public:
BOOL InitSocket(void);
static DWORD WINAPI RecvProc(LPVOID lpParameter);
//如果需要定义为成员函数时,必须是静态的。因为静态成员函数不属于任何对象
private:
SOCKET m_socket;
public:
afx_msg void OnBnClickedBtnSend();
};
3、CChartDlg.cpp
BEGIN_MESSAGE_MAP(CChartDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_RECVDATA, OnRecvData)
ON_BN_CLICKED(ID_BTN_SEND, &CChartDlg::OnBnClickedBtnSend)
END_MESSAGE_MAP()
// CChartDlg 消息处理程序
BOOL CChartDlg::OnInitDialog()
{
CDialog::OnInitDialog();
//....
// TODO: 在此添加额外的初始化代码
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->SetAddress(127,0,0,1);
InitSocket();
RecvParam *pRecvParam = new RecvParam;
pRecvParam->sock = m_socket;
pRecvParam->hwnd = m_hWnd;
HANDLE hThread = CreateThread(NULL, 0, RecvProc, (LPVOID)pRecvParam, 0, NULL); //创建一个线程
CloseHandle(hThread);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
BOOL CChartDlg::InitSocket(void)
{
//初始化套接字
m_socket = socket(AF_INET, SOCK_DGRAM, 0); //UDP
if (INVALID_SOCKET == m_socket)
{
AfxMessageBox(_T("socket fail"));
return FALSE;
}
SOCKADDR_IN addrSock;
addrSock.sin_family = AF_INET;
addrSock.sin_port = htons(6000);
addrSock.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
int ret = bind(m_socket, (SOCKADDR*)&addrSock, sizeof(SOCKADDR));
if (SOCKET_ERROR == ret)
{
closesocket(m_socket);
AfxMessageBox(_T("bind fail"));
return FALSE;
}
return TRUE;
}
LRESULT CChartDlg::OnRecvData(WPARAM wParam, LPARAM lParam)
{
CString str((char*)lParam);
CString strTemp;
GetDlgItemText(IDC_EDIT_RECV, strTemp);
str.Append(_T("\r\n"));
str.Append(strTemp);
SetDlgItemText(IDC_EDIT_RECV, str);
return TRUE;
}
DWORD WINAPI CChartDlg::RecvProc(LPVOID lpParameter)
{
SOCKET sock = ((RecvParam*)lpParameter)->sock;
HWND hwnd = ((RecvParam*)lpParameter)->hwnd;
SOCKADDR_IN addrFrom;
int len = sizeof(SOCKADDR);
char recvBuf[200]; //接收数据
char tempBuf[200];
int retVal;
while(TRUE)
{
retVal = recvfrom(sock, recvBuf, 200, 0, (SOCKADDR*)&addrFrom, &len);
if (SOCKET_ERROR == retVal)
{
break;
}
sprintf(tempBuf, "%s say: %s", inet_ntoa(addrFrom.sin_addr), recvBuf); //格式化数据
::PostMessage(hwnd, WM_RECVDATA, 0, (LPARAM)tempBuf); //发送一个消息
}
return 0;
}
void CChartDlg::OnBnClickedBtnSend()
{
// 发送消息
DWORD dwIP;
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);//获取控件上填写的IP
SOCKADDR_IN addrTo;
addrTo.sin_family = AF_INET;
addrTo.sin_port = htons(6000);
addrTo.sin_addr.S_un.S_addr = htonl(dwIP);
CString strSend;
GetDlgItemText(IDC_EDIT_SEND, strSend);
sendto(m_socket, strSend, strSend.GetLength() + 1, 0,
(SOCKADDR*)&addrTo, sizeof(SOCKADDR));
SetDlgItemText(IDC_EDIT_SEND, _T(""));
}