主程序
// QQDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "QQ.h"
#include "QQDlg.h"
#include "afxdialogex.h"
#include "Inc.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CQQDlg 对话框
CQQDlg::CQQDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CQQDlg::IDD, pParent)
{
bShowAll = FALSE;
bShutDown = FALSE;
m_ListenSock = INVALID_SOCKET;
m_hListenThread = NULL;
m_ConnectSock = INVALID_SOCKET;
m_bIsServer = -1;
m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);
}
void CQQDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_SHOW_MSG, m_MsgEdit);
}
BEGIN_MESSAGE_MAP(CQQDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_NETSET, &CQQDlg::OnBnClickedNetset)
ON_BN_CLICKED(IDC_START_SERVER, &CQQDlg::OnBnClickedStartServer)
ON_BN_CLICKED(IDC_START_CLIENT, &CQQDlg::OnBnClickedStartClient)
ON_BN_CLICKED(IDC_SENDMSG, &CQQDlg::OnBnClickedSendmsg)
ON_EN_CHANGE(IDC_INPUT_MSG, &CQQDlg::OnEnChangeInputMsg)
ON_BN_CLICKED(IDC_STOP_CLIENT, &CQQDlg::OnBnClickedStopClient)
ON_BN_CLICKED(IDC_STOP_SERVER, &CQQDlg::OnBnClickedStopServer)
ON_BN_CLICKED(IDC_RADIO_CLIENT, &CQQDlg::OnBnClickedRadioClient)
ON_BN_CLICKED(IDC_RADIO_SERVER, &CQQDlg::OnBnClickedRadioServer)
ON_BN_CLICKED(IDCANCEL, &CQQDlg::OnBnClickedCancel)
ON_BN_CLICKED(IDC_OTHER, &CQQDlg::OnBnClickedOther)
ON_COMMAND(ID_MENU_TrayIcon, &CQQDlg::OnMenuTrayicon)
ON_MESSAGE(WM_TRAYICON_MSG, OnTrayCallBackMsg)
ON_COMMAND(ID_SHOW, &CQQDlg::OnShow)
ON_COMMAND(ID_MENU_EXIT, &CQQDlg::OnMenuExit)
END_MESSAGE_MAP()
// CQQDlg 消息处理程序
BOOL CQQDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
DlgAllInit();
ExtendDialog(FALSE);
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CQQDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CQQDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CQQDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CQQDlg::DlgAllInit()
{
//EnableWindow(this, FALSE);整个窗口无效
/*
void CheckRadioButton(int nIDFirstButton, int nIDLastButton, int nIDCheckButton); //选中某个单选框
*/
CheckRadioButton(IDC_RADIO_CLIENT, IDC_RADIO_SERVER, IDC_RADIO_CLIENT);//最后一个选中;
SetDlgItemText(IDC_IP_ADDR, _T("127.0.0.1"));
SetDlgItemText(IDC_CONNECT_PORT, _T("5566"));
SetDlgItemText(IDC_LISTEN_PORT, _T("5566"));
EnableWindow(IDC_STOP_CLIENT, FALSE);
EnableWindow(IDC_LISTEN_PORT, FALSE);
EnableWindow(IDC_STOP_SERVER, FALSE);
EnableWindow(IDC_START_SERVER, FALSE);
EnableWindow(IDC_STATIC_LISTEN_PORT, FALSE);
EnableWindow(IDC_SENDMSG,FALSE);
//AfxMessageBox(_T("hello VA_X"));
EnableWindow(IDC_SENDMSG, FALSE);
}
BOOL CQQDlg::EnableWindow(UINT uID, BOOL bEnable)
{
/*
三种方法实现按钮的启用 or 禁用 --- 实际原理是一样的
*/
/*********************************************************************************/
/*
BOOL EnableWindow(BOOL bEnable = TRUE); //启用 or 禁用某个窗口
CWnd* GetDlgItem(int nID) //获得某窗口的指针
HWND GetSafeHwnd() //获得某窗口的句柄
*/
return GetDlgItem(uID)->EnableWindow(bEnable);
//::EnableWindow(GetDlgItem(IDC_START_SERVER)->GetSafeHwnd(),bEnable);
}
void CQQDlg::ExtendDialog(BOOL bShow)
{
/*
生成一个位置、长和宽都是0的CRect类对象
这一般用来做CRect对象初始化用的.
第一个参数是矩形左上角点的X,第二个参数是矩形左上角点的Y,第三个是X轴的长度,第四个是Y轴的长度。
*/
static CRect m_DlgRectLarge(0,0,0,0);
static CRect m_DlgRectSmall(0,0,0,0);
static CRect m_GroupRectLarge(0 ,0,0,0);
static CRect m_GroupRectSmall(0,0,0,0);
if (m_DlgRectLarge.IsRectNull())
{
//每一次都重新设置窗口的大小
GetWindowRect(&m_DlgRectLarge);//获取窗口总大小
m_DlgRectSmall = m_DlgRectLarge;
m_DlgRectSmall.right-= 250;
//获取当前IDC_FRAME的窗口句柄
::GetWindowRect(GetDlgItem(IDC_FRAME)->GetSafeHwnd(),&m_GroupRectLarge);
m_GroupRectSmall = m_GroupRectLarge;
m_GroupRectSmall.right-= 250;
}
//加上::表示此函数不属于任何类,而是Windows API函数
if (bShow)
{
bShowAll = TRUE;
SetWindowPos(NULL,0,0,m_DlgRectLarge.Width(),m_DlgRectLarge.Height(),SWP_NOZORDER|SWP_NOMOVE);
::SetWindowPos(GetDlgItem(IDC_FRAME)->GetSafeHwnd(),NULL,0,0,m_GroupRectLarge.Width(),m_GroupRectLarge.Height(),SWP_NOMOVE|SWP_NOZORDER);
}
else
{
bShowAll = FALSE;
SetWindowPos(NULL,0,0,m_DlgRectSmall.Width(),m_DlgRectSmall.Height(),SWP_NOZORDER|SWP_NOMOVE);
::SetWindowPos(GetDlgItem(IDC_FRAME)->GetSafeHwnd(),NULL,0,0,m_GroupRectSmall.Width(),m_GroupRectSmall.Height(),SWP_NOMOVE|SWP_NOZORDER);
}
}
void CQQDlg::OnBnClickedNetset()
{
// TODO: 在此添加控件通知处理程序代码
//ShellExecute(NULL,_T("open"),_T("www.baidu.com"),NULL,NULL,SW_SHOWNORMAL);
if (bShowAll)
{
ExtendDialog(FALSE);
}
else
{
ExtendDialog(TRUE);
}
}
void CQQDlg::ShowMsg(CString strMsg)
{
m_MsgEdit.SetSel(-1, -1);
m_MsgEdit.ReplaceSel(strMsg+_T("\r\n"));
}
void CQQDlg::SendClientsMsg(CString strMsg, CClientItem *pNotSend)
{
TCHAR szBuf[MAX_BUF_SIZE] = {0};
_tcscpy_s(szBuf, MAX_BUF_SIZE, strMsg);
for( INT_PTR idx = 0; idx < m_ClientArray.GetCount(); idx++ ) {
if ( !pNotSend || pNotSend->m_Socket != m_ClientArray.GetAt(idx).m_Socket || pNotSend->hThread != m_ClientArray.GetAt(idx).hThread ||
pNotSend->m_strIp != m_ClientArray.GetAt(idx).m_strIp) {
send(m_ClientArray.GetAt(idx).m_Socket, (char *)szBuf, _tcslen(szBuf)*sizeof(TCHAR), 0);
}
}
}
void CQQDlg::RemoveClientFromArray(CClientItem in_Item)
{
for( int idx = 0; idx <m_ClientArray.GetCount(); idx++ ) {
CClientItem tItem = m_ClientArray.GetAt(idx);
if ( tItem.m_Socket == in_Item.m_Socket &&
tItem.hThread == in_Item.hThread &&
tItem.m_strIp == in_Item.m_strIp ) {
m_ClientArray.RemoveAt(idx);
}
}
}
void CQQDlg::OnBnClickedStartServer()
{
CreateThread(NULL, 0, ListenThreadFunc, this,0, NULL);
// TODO: 在此添加控件通知处理程序代码
/*m_ListenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ( m_ListenSock == INVALID_SOCKET ) {
AfxMessageBox(_T("新建SOCKET失败!"));
return;
}
UINT uPort = GetDlgItemInt(IDC_LISTEN_PORT);
if ( uPort <= 0 || uPort > 65535 ) {
AfxMessageBox(_T("请输入合适的端口:1 - 65535"));
goto __Error_End;
}
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = INADDR_ANY;
service.sin_port = htons(uPort);
if (bind(m_ListenSock, (sockaddr*)&service,sizeof(sockaddr_in)) == SOCKET_ERROR)
{
AfxMessageBox(_T("绑定端口失败!"));
goto __Error_End;
}
if (listen(m_ListenSock,5) == SOCKET_ERROR)
{
AfxMessageBox(_T("监听失败!"));
goto __Error_End;
}
sockaddr_in clientAddr;
int iLen = sizeof(sockaddr_in);
SOCKET accSock = accept(m_ListenSock, (struct sockaddr *)&clientAddr, &iLen);
if (accSock == INVALID_SOCKET)
{
AfxMessageBox(_T("接受客户端失败!"));
goto __Error_End;
}
__Error_End:
closesocket(m_ListenSock);
*/
}
void CQQDlg::OnBnClickedStartClient()
{
// TODO: 在此添加控件通知处理程序代码
m_hConnectThred = CreateThread(NULL, 0, ConnectThreadFunc, this, 0, NULL);
}
void CQQDlg::OnBnClickedSendmsg()
{
// TODO: 在此添加控件通知处理程序代码
CString strMsg;
GetDlgItemText(IDC_INPUT_MSG, strMsg);
if ( m_bIsServer == TRUE ) {
strMsg = _T("服务器:>") + strMsg;
ShowMsg(strMsg);
SendClientsMsg(strMsg);
}else if (m_bIsServer == FALSE) {
CString strTmp = _T("本地客户端:>") + strMsg;
ShowMsg(strTmp);
int iSend = send(m_ConnectSock, (char *)strMsg.GetBuffer(), strMsg.GetLength()*sizeof(TCHAR), 0);
strMsg.ReleaseBuffer();
}
else{
AfxMessageBox(_T("请你先进入聊天室!"));
}
SetDlgItemText(IDC_INPUT_MSG, _T(""));
}
void CQQDlg::OnEnChangeInputMsg()
{
// TODO: 如果该控件是 RICHEDIT 控件,它将不
// 发送此通知,除非重写 CDialogEx::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
// TODO: 在此添加控件通知处理程序代码
CString strMsg;
GetDlgItemText(IDC_INPUT_MSG, strMsg);
if (strMsg.IsEmpty())
{
EnableWindow(IDC_SENDMSG, FALSE);
}
else
{
EnableWindow(IDC_SENDMSG, TRUE);
}
}
void CQQDlg::StopClient()
{
bShutDown = TRUE;
DWORD dwRet = WaitForSingleObject(m_hConnectThred, 1000);
if ( dwRet != WAIT_OBJECT_0 ) {
TerminateThread(m_hConnectThred, -1);
closesocket(m_ConnectSock);
}
m_hConnectThred = NULL;
m_ConnectSock = INVALID_SOCKET;
m_bIsServer = -1;
bShutDown = FALSE;
}
void CQQDlg::StopServer()
{
UINT nCount = m_ClientArray.GetCount();
HANDLE *m_pHandles = new HANDLE[nCount+1];
m_pHandles[0] = m_hListenThread;
for( int idx = 0; idx < nCount; idx++ ) {
m_pHandles[idx+1] = m_ClientArray.GetAt(idx).hThread;
}
bShutDown = TRUE;
DWORD dwRet = WaitForMultipleObjects(nCount+1, m_pHandles, TRUE, 1000);
if ( dwRet != WAIT_OBJECT_0 ) {
for( INT_PTR i = 0; i < m_ClientArray.GetCount(); i++ ) {
TerminateThread(m_ClientArray.GetAt(i).hThread, -1);
closesocket(m_ClientArray.GetAt(i).m_Socket);
}
TerminateThread(m_hListenThread, -1);
closesocket(m_ListenSock);
}
delete [] m_pHandles;
m_hListenThread = NULL;
m_ListenSock = INVALID_SOCKET;
m_bIsServer = -1;
bShutDown = FALSE;
}
void CQQDlg::OnBnClickedStopClient()
{
// TODO: 在此添加控件通知处理程序代码
StopClient();
ShowMsg(_T("停止客户端成功!"));
EnableWindow(IDC_START_CLIENT);
EnableWindow(IDC_STOP_CLIENT, FALSE);
}
void CQQDlg::OnBnClickedStopServer()
{
// TODO: 在此添加控件通知处理程序代码
StopServer();
ShowMsg(_T("停止服务器成功!"));
EnableWindow(IDC_START_SERVER);
EnableWindow(IDC_STOP_SERVER, FALSE);
}
void CQQDlg::OnBnClickedRadioClient()
{
// TODO: 在此添加控件通知处理程序代码
int iRet = -1;
if ( m_bIsServer == TRUE ) {
int iRet = MessageBox(_T("您是聊天室的服务器端,如果您退出,所有的客户端都将掉线!\r\n您确定退出吗?"), _T("提示"), MB_OKCANCEL | MB_ICONWARNING);
if ( iRet == IDOK ) {
StopServer();
}else{
CheckRadioButton(IDC_RADIO_CLIENT, IDC_RADIO_SERVER, IDC_RADIO_SERVER);
}
}
if ( iRet == IDOK || m_bIsServer == -1 ) {
EnableWindow(IDC_IP_ADDR);
EnableWindow(IDC_CONNECT_PORT);
EnableWindow(IDC_STATIC_SERVER_IP);
EnableWindow(IDC_STATIC_SERVER_PORT);
EnableWindow(IDC_START_CLIENT);
EnableWindow(IDC_STOP_CLIENT, FALSE);
EnableWindow(IDC_LISTEN_PORT, FALSE);
EnableWindow(IDC_STOP_SERVER, FALSE);
EnableWindow(IDC_START_SERVER, FALSE);
EnableWindow(IDC_STATIC_LISTEN_PORT, FALSE);
}
}
void CQQDlg::OnBnClickedRadioServer()
{
// TODO: 在此添加控件通知处理程序代码
int iRet = -1;
if ( m_bIsServer == FALSE ) {
int iRet = MessageBox(_T("您正在聊天室中,确定退出吗?"), _T("提示"), MB_OKCANCEL | MB_ICONWARNING);
if ( iRet == IDOK ) {
StopClient();
}else{
CheckRadioButton(IDC_RADIO_CLIENT, IDC_RADIO_SERVER, IDC_RADIO_CLIENT);
}
}
if ( iRet == IDOK || m_bIsServer == -1) {
EnableWindow(IDC_LISTEN_PORT);
EnableWindow(IDC_STOP_SERVER, FALSE);
EnableWindow(IDC_START_SERVER);
EnableWindow(IDC_STATIC_LISTEN_PORT);
EnableWindow(IDC_IP_ADDR, FALSE);
EnableWindow(IDC_CONNECT_PORT, FALSE);
EnableWindow(IDC_STATIC_SERVER_IP, FALSE);
EnableWindow(IDC_STATIC_SERVER_PORT, FALSE);
EnableWindow(IDC_START_CLIENT, FALSE);
EnableWindow(IDC_STOP_CLIENT, FALSE);
}
}
void CQQDlg::OnBnClickedCancel()
{
// TODO: 在此添加控件通知处理程序代码
if ( m_bIsServer == TRUE ) {
StopServer();
}else if ( m_bIsServer == FALSE ) {
StopClient();
}
CDialogEx::OnCancel();
}
void CQQDlg::OnBnClickedOther()
{
// TODO: 在此添加控件通知处理程序代码
CPoint pt;
CRect mRect;
CMenu mMenu, *pMenu = NULL;
GetDlgItem(IDC_OTHER)->GetWindowRect(&mRect);
pt = mRect.BottomRight();
pt.y = mRect.top+5;
mMenu.LoadMenu(IDR_MENU1);
pMenu = mMenu.GetSubMenu(0);
pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this);
}
BOOL CQQDlg::TrayMyIcon(BOOL bAdd)
{
BOOL bRet = FALSE;
NOTIFYICONDATA tnd;
tnd.cbSize = sizeof(NOTIFYICONDATA);
tnd.hWnd = GetSafeHwnd();
tnd.uID = IDI_ICON1;
if ( bAdd == TRUE ) {
tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
tnd.uCallbackMessage = WM_TRAYICON_MSG;
tnd.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
_tcscpy_s(tnd.szTip, sizeof(tnd.szTip), _T("聊天室v1.0"));
ShowWindow(SW_MINIMIZE);
ShowWindow(SW_HIDE);
bRet = Shell_NotifyIcon(NIM_ADD, &tnd);
}else{
ShowWindow(SW_SHOWNA);
SetForegroundWindow();
bRet = Shell_NotifyIcon(NIM_DELETE, &tnd);
}
return bRet;
}
void CQQDlg::OnMenuTrayicon()
{
// TODO: 在此添加命令处理程序代码
TrayMyIcon();
}
LRESULT CQQDlg::OnTrayCallBackMsg(WPARAM wparam, LPARAM lparam)
{
switch(lparam)
{
case WM_RBUTTONUP:
{
CMenu mMenu, *pMenu = NULL;
CPoint pt;
mMenu.LoadMenu(IDR_MENU2);
pMenu = mMenu.GetSubMenu(0);
GetCursorPos(&pt);
SetForegroundWindow();
pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this);
break;
}
case WM_LBUTTONDBLCLK:
ShowWindow(SW_RESTORE);
SetForegroundWindow();
TrayMyIcon(FALSE);
break;
default:break;
}
return NULL;
}
void CQQDlg::OnShow()
{
// TODO: 在此添加命令处理程序代码
ShowWindow(SW_RESTORE);
TrayMyIcon(FALSE);
}
void CQQDlg::OnMenuExit()
{
// TODO: 在此添加命令处理程序代码
TrayMyIcon(FALSE);
OnBnClickedCancel();
}
#include "stdafx.h"
#include "QQDlg.h"
BOOL SOCKET_Select(SOCKET hSock, int nTimeOut, BOOL bRead)
{
fd_set fdset;
timeval tv;
FD_ZERO(&fdset);
FD_SET(hSock, &fdset);
nTimeOut = nTimeOut > 1000 ? 1000:nTimeOut;
tv.tv_sec = 0;
tv.tv_usec = nTimeOut;
int iRet = 0;
if (bRead)
{
iRet = select(0, &fdset, NULL, NULL, &tv);
}
else
{
iRet = select(0,NULL, &fdset, NULL,&tv);
}
if (iRet < 0)
{
return FALSE;
}
else if (FD_ISSET(hSock, &fdset))
{
return TRUE;
}
}
DWORD WINAPI ListenThreadFunc(LPVOID pParam)
{
CQQDlg *pChatRoom = (CQQDlg *)pParam;
ASSERT(pChatRoom != NULL);
pChatRoom->m_ListenSock = socket(AF_INET , SOCK_STREAM , IPPROTO_TCP);
if ( pChatRoom->m_ListenSock == INVALID_SOCKET ) {
AfxMessageBox(_T("新建Socket失败!"));
return FALSE;
}
int iPort = pChatRoom->GetDlgItemInt(IDC_LISTEN_PORT);
if ( iPort <= 0 || iPort > 65535 ) {
AfxMessageBox(_T("请输入合适的端口:1 - 65535"));
goto __Error_End;
}
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = INADDR_ANY;
service.sin_port = htons(iPort);
if ( bind(pChatRoom->m_ListenSock, (sockaddr*)&service, sizeof(sockaddr_in)) == SOCKET_ERROR ) {
AfxMessageBox(_T("绑定端口失败!"));
goto __Error_End;
}
if( listen(pChatRoom->m_ListenSock, 5) == SOCKET_ERROR ) {
AfxMessageBox(_T("监听失败!"));
goto __Error_End;
}
pChatRoom->ShowMsg(_T("系统信息:启动服务器成功!"));
pChatRoom->m_bIsServer = TRUE;
pChatRoom->EnableWindow(IDC_START_SERVER, FALSE);
pChatRoom->EnableWindow(IDC_STOP_SERVER);
while( TRUE && !(pChatRoom->bShutDown)) {
if ( SOCKET_Select(pChatRoom->m_ListenSock, 100, TRUE) ) {
sockaddr_in clientAddr;
int iLen = sizeof(sockaddr_in);
SOCKET accSock = accept(pChatRoom->m_ListenSock, (struct sockaddr *)&clientAddr , &iLen);
if (accSock == INVALID_SOCKET) {
continue;
}
CClientItem tItem;
tItem.m_Socket = accSock;
tItem.m_pMainWnd = pChatRoom;
tItem.m_strIp = inet_ntoa(clientAddr.sin_addr);//网络字节序转化为本机点分IP地址
INT_PTR idx = pChatRoom->m_ClientArray.Add(tItem);
tItem.hThread = CreateThread(NULL, 0, ClientThreadProc, &(pChatRoom->m_ClientArray.GetAt(idx)), CREATE_SUSPENDED, NULL);
pChatRoom->m_ClientArray.GetAt(idx).hThread = tItem.hThread;
/*恢复线程的句柄使用该函数能够激活线程的运行*/
ResumeThread(tItem.hThread);
CString strMsg;
strMsg = _T("客户端") + tItem.m_strIp + _T("进入聊天室!");
pChatRoom->ShowMsg(strMsg);
pChatRoom->SendClientsMsg(strMsg, &tItem);
//pChatRoom->SendMessage(strMsg, &tItem);
//做一些其他操作……
Sleep(100);
}
}
__Error_End:
closesocket(pChatRoom->m_ListenSock);
return TRUE;
}
DWORD WINAPI ClientThreadProc(LPVOID lpParameter)
{
CString strMsg;
CClientItem m_ClientItem = *(CClientItem *)lpParameter;
while( TRUE && !(m_ClientItem.m_pMainWnd->bShutDown)) {
if ( SOCKET_Select(m_ClientItem.m_Socket, 100, TRUE) ) {
TCHAR szBuf[MAX_BUF_SIZE] = {0};
int iRet = recv(m_ClientItem.m_Socket, (char *)szBuf, MAX_BUF_SIZE, 0);
if ( iRet > 0 ) {
//right;
strMsg = szBuf;
strMsg = _T("客户端:") + m_ClientItem.m_strIp + _T(">") + strMsg;
m_ClientItem.m_pMainWnd->ShowMsg(strMsg);
m_ClientItem.m_pMainWnd->SendClientsMsg(strMsg, &m_ClientItem);
}else{
//close socket;
strMsg = _T("客户端:") + m_ClientItem.m_strIp + _T(" 离开了聊天室!");
m_ClientItem.m_pMainWnd->ShowMsg(strMsg);
m_ClientItem.m_pMainWnd->RemoveClientFromArray(m_ClientItem);
m_ClientItem.m_pMainWnd->SendClientsMsg(strMsg, &m_ClientItem);
break;
}
}
Sleep(500);
}
return TRUE;
}
#include "stdafx.h"
#include "QQDlg.h"
#include "Inc.h"
DWORD WINAPI ConnectThreadFunc(LPVOID pParam)
{
CQQDlg *pChatRoom = (CQQDlg *)pParam;
ASSERT(pChatRoom != NULL);
pChatRoom->m_ConnectSock = socket(AF_INET , SOCK_STREAM , IPPROTO_TCP);
if ( pChatRoom->m_ConnectSock == INVALID_SOCKET ) {
AfxMessageBox(_T("新建Socket失败!"));
return FALSE;
}
CString strServIp;
pChatRoom->GetDlgItemText(IDC_IP_ADDR, strServIp);
int iPort = pChatRoom->GetDlgItemInt(IDC_CONNECT_PORT);
if ( iPort <= 0 || iPort > 65535 ) {
AfxMessageBox(_T("请输入合适的端口:1 - 65535"));
goto __Error_End;
}
char szIpAddr[16] = {0};
USES_CONVERSION;
strcpy_s(szIpAddr, 16, T2A(strServIp));
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(iPort);
server.sin_addr.s_addr = inet_addr(szIpAddr);
if ( connect(pChatRoom->m_ConnectSock, (struct sockaddr *)&server, sizeof(struct sockaddr)) == SOCKET_ERROR ) {
AfxMessageBox(_T("连接失败,请重试!"));
goto __Error_End;
}
pChatRoom->m_bIsServer = FALSE;
pChatRoom->ShowMsg(_T("系统信息:连接服务器成功!"));
while( TRUE&&!(pChatRoom->bShutDown)) {
if ( SOCKET_Select(pChatRoom->m_ConnectSock) ) {
TCHAR szBuf[MAX_BUF_SIZE] = {0};
int iRet = recv(pChatRoom->m_ConnectSock, (char *)szBuf, MAX_BUF_SIZE, 0);
if ( iRet > 0 ) {
//right;
pChatRoom->ShowMsg(szBuf);
}else{
//close socket;
pChatRoom->ShowMsg(_T("聊天室服务器已停止,请重新进行连接!"));
break;
}
}
Sleep(500);
}
__Error_End:
closesocket(pChatRoom->m_ConnectSock);
return TRUE;
}
#pragma once
class CQQDlg;
#define MAX_BUF_SIZE 1024
#define WM_TRAYICON_MSG (WM_USER+100)
class CClientItem
{
public:
CString m_strIp;
SOCKET m_Socket;
HANDLE hThread;
CQQDlg *m_pMainWnd;
CClientItem()
{
m_pMainWnd = NULL;
m_Socket = INVALID_SOCKET;
hThread =NULL;
}
};
DWORD WINAPI ListenThreadFunc(LPVOID pParam);
DWORD WINAPI ClientThreadProc(LPVOID lpParameter);
DWORD WINAPI ConnectThreadFunc(LPVOID pParam);
BOOL SOCKET_Select(SOCKET hSocket, int nTimeOut = 100, BOOL bRead = FALSE);