github源代码地址: https://github.com/duijiudanggecl/VC-.git
ServerSocket.cpp
此类继承于 CSocket
CServerSocket::CServerSocket()
{
}
CServerSocket::~CServerSocket()
{
}
void CServerSocket::OnReceive(int nErrorCode)
{
m_pDlg->RecvData(this); // 接收数据
CSocket::OnReceive(nErrorCode);
}
void CServerSocket::OnClose(int nErrorCode)
{
m_pDlg -> RemoveClient(this); // 删除下线用户
CSocket::OnClose(nErrorCode);
}
void CServerSocket::OnAccept(int nErrorCode)
{
m_pDlg->AddClient(); //添加上线用户
CSocket::OnAccept(nErrorCode);
}
主对话框:
-
CServerDlg::CServerDlg(CWnd* pParent /
=NULL/)
-
CDialogEx(IDD_SERVER_DIALOG, pParent)
, m_port(0)
, m_usercount(0)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CServerDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_PORT, port);
DDX_Control(pDX, IDC_EventRecord, m_event);
DDX_Control(pDX, IDC_USERCOUNT, usercount);
}
BEGIN_MESSAGE_MAP(CServerDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_StateServer, &CServerDlg::OnBnClickedStateserver)
ON_BN_CLICKED(IDC_SEND, &CServerDlg::OnBnClickedSend)
END_MESSAGE_MAP()
// CServerDlg 消息处理程序
BOOL CServerDlg::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); // 设置小图标
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CServerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CServerDlg::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 CServerDlg::OnQueryDragIcon()
{
return static_cast(m_hIcon);
}
void CServerDlg::OnBnClickedStateserver()
{
// TODO: 在此添加控件通知处理程序代码
//SetDlgItemInt(IDC_PORT, m_port);
//SetDlgItemInt(IDC_USERCOUNT, m_usercount);
CString strText(_T(""));
GetDlgItemText(IDC_PORT, strText);
//double val1 = _tcstod(strText, NULL); // 浮点数用这个
short m_port = _ttoi(strText); // 整数用这个
if (m_connect)
{
delete listenSocket;
listenSocket = NULL;
m_connect = false;
SetDlgItemText(IDC_StateServer, _T("打开服务器"));
UpdateEvent(_T("系统关闭服务器."));
return;
}
listenSocket = new CServerSocket();
listenSocket->m_pDlg = this;
// 指定对话框为主对话框,不能少了这句
UpdateData(true);
if (!listenSocket->Create(m_port)) //8000
// 创建服务器的套接字,IP地址默认本机IP
{
AfxMessageBox(_T("创建套接字错误!"));
listenSocket->Close();
return;
}
if (!listenSocket->Listen())
{
AfxMessageBox(_T("监听失败!"));
listenSocket->Close();
return;
}
m_connect = true;
SetDlgItemText(IDC_StateServer, _T("关闭服务器"));
UpdateEvent(_T("系统打开服务器."));
}
void CServerDlg::AddClient()
{
CServerSocket *pSocket = new CServerSocket;
pSocket->m_pDlg = this;
listenSocket->Accept(*pSocket);
pSocket->AsyncSelect(FD_READ | FD_WRITE | FD_CLOSE);
m_clientList.AddTail(pSocket); //将所有客户连接加入到链表中
m_usercount = m_clientList.GetCount();
char ary[100] = "";
_itoa_s(m_usercount, ary, 10);//十进制-22
CString str;
//str = T2A(ary);
str= CString(ary);
SetDlgItemText(IDC_USERCOUNT, str);
UpdateData(false);
UpdateEvent(_T("用户连接服务器."));
SendMSG(_T("Chen"));
}
void CServerDlg::RemoveClient(CServerSocket* pSocket)
{
POSITION nPos = m_clientList.GetHeadPosition();
POSITION nTmpPos = nPos;
while (nPos)
{
CServerSocket* pSockItem = (CServerSocket*)m_clientList.GetNext(nPos);
if (pSockItem->m_hSocket == pSocket->m_hSocket)
{
pSockItem->Close();
delete pSockItem;
m_clientList.RemoveAt(nTmpPos);
m_usercount = m_clientList.GetCount();
char ary[100] = "";
_itoa_s(m_usercount, ary, 10);//十进制-22
CString str;
//str = T2A(ary);
str = CString(ary);
SetDlgItemText(IDC_USERCOUNT, str);
UpdateData(false);
UpdateEvent(_T("用户离开."));
return;
}
nTmpPos = nPos;
}
}
#define OUTINFO_0_PARAM(fmt) {CHAR sOut[256];CHAR sfmt[50];sprintf_s(sfmt,"%s%s",“INFO–”,fmt);sprintf_s(sOut,(sfmt));OutputDebugStringA(sOut);}
#define OUTINFO_1_PARAM(fmt, var) { CHAR sOut[256]; CHAR sfmt[50]; sprintf_s(sfmt, “%s%s”, “INFO–”, fmt); sprintf_s(sOut, (sfmt), var); OutputDebugStringA(sOut); }
#define OUTINFO_2_PARAM(fmt, var1, var2) { CHAR sOut[256]; CHAR sfmt[50]; sprintf_s(sfmt, “%s%s”, “INFO–”, fmt); sprintf_s(sOut, (sfmt), var1, var2); OutputDebugStringA(sOut); }
#define OUTINFO_3_PARAM(fmt, var1, var2, var3) { CHAR sOut[256]; CHAR sfmt[50]; sprintf_s(sfmt, “%s%s”, “INFO–”, fmt); sprintf_s(sOut, (sfmt), var1, var2, var3); OutputDebugStringA(sOut); }
void CServerDlg::RecvData(CServerSocket* pSocket)
{
char* pData = NULL;
pData = new char[1024];
memset(pData, 0, sizeof(char) * 1024);
UCHAR leng = 0;
CString str;
if (pSocket->Receive(pData, 1024, 0) != SOCKET_ERROR)
{
str = pData;
//USES_CONVERSION;
//调用函数,T2A和W2A均支持ATL和MFC中的字符转换
//char * pFileName = T2A(str);
//OUTINFO_1_PARAM("---%s-----\n", pFileName);
UpdateEvent(str);
//ControlPC(str); // 依据指令控制电脑
//SendMSG(str); // 转发数据给所有用户,包括发送数据的用户
}
delete pData;
pData = NULL;
}
void CServerDlg::UpdateEvent(CString str)
{
CString string;
CTime time = CTime::GetCurrentTime();
// 获取系统当前时间
str += _T("\r\n");
// 用于换行显示日志
string = time.Format(_T("%Y/%m/%d %H:%M:%S ")) + str;
// 格式化当前时间
int lastLine = m_event.LineIndex(m_event.GetLineCount() - 1);
//获取编辑框最后一行索引
m_event.SetSel(lastLine + 1, lastLine + 2, 0);
//选择编辑框最后一行
m_event.ReplaceSel(string); //替换所选那一行的内容
}
BOOL CServerDlg::WChar2MByte(LPCWSTR srcBuff, LPSTR destBuff, int nlen)
{
int n = 0;
n = WideCharToMultiByte(CP_OEMCP, 0, srcBuff, -1, destBuff, 0, 0, FALSE);
if (n<nlen)return FALSE;
WideCharToMultiByte(CP_OEMCP, 0, srcBuff, -1, destBuff, nlen, 0, FALSE);
return TRUE;
}
void CServerDlg::SendMSG(CString str)
{
char *pSend = new char[str.GetLength()];
memset(pSend, 0, str.GetLength() * sizeof(char));
if (!WChar2MByte(str.GetBuffer(0), pSend, str.GetLength()))
{
AfxMessageBox(_T("字符转换失败"));
delete pSend;
return;
}
POSITION nPos = m_clientList.GetHeadPosition();
while (nPos)
{
CServerSocket* pTemp = (CServerSocket*)m_clientList.GetNext(nPos);
pTemp->Send(pSend, str.GetLength());
}
delete pSend;
}
void CServerDlg::ControlPC(CString AndroidControl)
{
if (AndroidControl == "mop") //打开播放器
{
ShellExecute(NULL, _T("open"), _T("C:\\Program Files (x86)\\KuGou\\KGMusic\\KuGou.exe"), NULL, NULL, SW_SHOWNORMAL);
}
else if (AndroidControl == "mcl") //关闭播放器
{
DWORD id_num;
HWND hWnd = ::FindWindow(_T("kugou_ui"), NULL);
GetWindowThreadProcessId(hWnd, &id_num);
//注意:第二个参数是进程的ID,返回值是线程的ID。
HANDLE hd = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id_num);
TerminateProcess(hd, 0);
}
else if (AndroidControl == "mpl" || AndroidControl == "mpa") //播放/暂停
{
keybd_event(VK_LMENU, 0, 0, 0);
keybd_event(VK_F5, 0, 0, 0);
keybd_event(VK_F5, 0, KEYEVENTF_KEYUP, 0);
keybd_event(VK_LMENU, 0, KEYEVENTF_KEYUP, 0);
}
}
BOOL CServerDlg::PreTranslateMessage(MSG* pMsg)
{
switch (pMsg->wParam)
{
case VK_RETURN:
case VK_ESCAPE:
return true; break;
}
return CDialogEx::PreTranslateMessage(pMsg);
}
void CServerDlg::OnBnClickedSend()
{
// TODO: 在此添加控件通知处理程序代码
CString str;
GetDlgItemText(IDC_EDIT_SEND, str);
//USES_CONVERSION;
//调用函数,T2A和W2A均支持ATL和MFC中的字符转换
//char * Tempstr = T2A(str);
//strcpy(pBuff, str.GetBuffer(0));
CServerDlg::SendMSG( str);
}