基于多线程的聊天室程序

   今天在学习了基于多线程的聊天室程序,另外还加上了socket编程。效果图如下

基于多线程的聊天室程序_第1张图片

代码如下:

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(""));
}

 

你可能感兴趣的:(多线程)