搜集的一些腾讯笔试题
今晚腾讯突然让我明天去参加实习生笔试,我差点都把这件事情给忘了。决定还是看一点面试题把。
1、请定义一个宏,比较两个数a、b的大小,不能使用大于、小于、if语句。
就是定义一个类似函数的宏,宏运算的结果来表示大于和小于。为了简单起见我们假设a,b为整型。
我是这样想的,如果可以用小于号的话,可以这么写:
#define compare(a,b) ((a-b)<0 ? -1 : ((a-b) == 0 ? 0 : 1))
这样一来的话:
compare(a,b) == -1表示a<b
compare(a,b) == 0表示a==b
compare(a,b) == 1表示a>b
但是如今不能用小于号,那么我们怎样不用小于号来判断一个数字是否小于0呢?我们可以用:abs(t) != t ? 1 : -1来表示。
也即如果abs(t) != t那么t<0,否则t>=0。也即t<0等价于(abs(t) != t ? 1 : -1) == 1那么前面的宏写成如下:
#define compare(a,b) ((abs(a-b) != (a-b) ? 1 : -1) == 1 ? -1 : ((a-b) == 0 ? 0 : 1))
代码:
2,有A、B、C、D四个人,要在夜里过一座桥。他们通过这座桥分别需要耗时1、2、5、10分钟,只有一支手电,并且同时最多只能两个人一起过桥。请问,如何安排,能够在17分钟内这四个人都过桥?
这个问题看起来有些难,但是想通了就比较容易。方法如下:
过桥时间上:A=1, B=2, C=3, D=4
1,A, B过桥:2分钟
2,A回来:1分钟
3,C, D过桥:10分钟
4,B回来:2分钟
5,A, B过桥:2分钟
一共17分钟。
3,如何输出源文件的标题和目前执行行的行数
这个要是没听过的,打死写不出来,在网上找了找:
4,两个数相乘,小数点后位数没有限制,请写一个高精度算法
这个算法思路比较容易,就是高精度的大整数相乘,但是要考虑小数点的位置。
假设记作a,b两个数字。分别存放到两个数组A,B中去,不考虑小数点。并且记录a, b小数点后分别有多少位记作:m, n。
然后将数组A, B按照大整数相乘的方法得到一个乘积存放在数组C中,C的长度是A,B长度之和。然后小数点位置就在倒数第m+n位置上。
这个只是答题思路,具体细节还要分外考虑。
5,写一个病毒
这个。。不知道病毒的定义是什么样子的。。你写一个程序,只要运行就不停的进行读写操作占用CPU和内存,而且删除系统文件,这个算是病毒吗??
我以前写过一个脚本修改注册表的,你把下面的代码拷贝到txt中,然后将后缀名改成reg点击试试,不知道win7下如何,xp屡试不爽。
REGEDIT4
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Folder\Hidden\SHOWALL]
"CheckedValue"=dword:00000000
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]
"DisableTaskMgr"=dword:00000001
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]
"DisableRegistryTools"=dword:00000001
这三个语句分别是禁止显示隐藏文件,禁用任务管理器以及禁用注册表。。然后俺就可以肆意的搞你了,这个挺无语的吧。修复方法:
REGEDIT4
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Folder\Hidden\SHOWALL]
"CheckedValue"=dword:00000001
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]
"DisableTaskMgr"=dword:00000000
6,不使用额外空间,将 A, B两链表的元素交叉归并
既然是链表,交换交换指针不就行了吗??没看出这题的难点,求高人指点。
我们假设不知道长度的情况下,将list2归并到list1,伪代码如下:
7,MFC 将树序列化 转存在数组或 链表中。
所谓序列化就是一种永久保存,一般就是将对象保存到一个文件中去,然后读取这个文件又可以完全得到原本的对象数据结构信息。
对于树的结构,是一种层次关系,这正好可以对应于xml文件。我们可以把树结构写进xml文件中去。
http://www.codeproject.com/KB/tree/ctreectrl_xml.aspx 给出了这种方法的实现。
就是对xml定一个规则,节点的层次用一个属性level来表示,例如 <Node level= "1 "> value </Node>。
在保存的时候,遍历TreeCtrl的节点,使用DOM方式动态的生成XML的节点,最后保存为xml文件。
在从xml文件中读取的时候,可以使用SAX的方式,根据level属性的值,动态的确定父子关系。
8,计算 a^b << 2 (运算符优先级问题)
<<运算优先级高于^
9,根据二叉树的先序,中序遍历求后序遍历
先根据先序我们得出整个树的根,然后在中序遍历中查找根所出现的位置(如果找不到这个根就是序列不合理的情况了),在中序应遍历中出现的根的左边的一定是树的左子树的结点,出现在右边的一定是右子树的结点,然后我们根据树的遍历规律可以在先序遍历中找到左子树的结点与右子树的结点,这样我们就而对了一个重复性的问题,就是已知先序与中序遍历构建树,递归便可以构建出整个树。
10,写出socks套接字 服务端 客户端 通讯程序
我就把我的毕设的一个基于异步选择IO模式的网络监控程序的部分代码贴一下把。注意这是基于异步非阻塞模式的。
客户端:
服务器端:
1、请定义一个宏,比较两个数a、b的大小,不能使用大于、小于、if语句。
就是定义一个类似函数的宏,宏运算的结果来表示大于和小于。为了简单起见我们假设a,b为整型。
我是这样想的,如果可以用小于号的话,可以这么写:
#define compare(a,b) ((a-b)<0 ? -1 : ((a-b) == 0 ? 0 : 1))
这样一来的话:
compare(a,b) == -1表示a<b
compare(a,b) == 0表示a==b
compare(a,b) == 1表示a>b
但是如今不能用小于号,那么我们怎样不用小于号来判断一个数字是否小于0呢?我们可以用:abs(t) != t ? 1 : -1来表示。
也即如果abs(t) != t那么t<0,否则t>=0。也即t<0等价于(abs(t) != t ? 1 : -1) == 1那么前面的宏写成如下:
#define compare(a,b) ((abs(a-b) != (a-b) ? 1 : -1) == 1 ? -1 : ((a-b) == 0 ? 0 : 1))
代码:
//利用宏比较大小
#include <iostream>
#include <cmath>
#define compare(a,b) ((abs(a-b) != (a-b) ? 1 : -1) == 1 ? -1 : ((a-b) == 0 ? 0 : 1))
int main()
{
int a1 = -1, b1 = 2, a2 = 3, b2 = 3, a3 = 4, b3= 2;
cout << compare(a1, b1) << endl << compare(a2, b2) << endl << compare(a3, b3) << endl;
return 0;
}
#include <iostream>
#include <cmath>
#define compare(a,b) ((abs(a-b) != (a-b) ? 1 : -1) == 1 ? -1 : ((a-b) == 0 ? 0 : 1))
int main()
{
int a1 = -1, b1 = 2, a2 = 3, b2 = 3, a3 = 4, b3= 2;
cout << compare(a1, b1) << endl << compare(a2, b2) << endl << compare(a3, b3) << endl;
return 0;
}
2,有A、B、C、D四个人,要在夜里过一座桥。他们通过这座桥分别需要耗时1、2、5、10分钟,只有一支手电,并且同时最多只能两个人一起过桥。请问,如何安排,能够在17分钟内这四个人都过桥?
这个问题看起来有些难,但是想通了就比较容易。方法如下:
过桥时间上:A=1, B=2, C=3, D=4
1,A, B过桥:2分钟
2,A回来:1分钟
3,C, D过桥:10分钟
4,B回来:2分钟
5,A, B过桥:2分钟
一共17分钟。
3,如何输出源文件的标题和目前执行行的行数
这个要是没听过的,打死写不出来,在网上找了找:
//C++
int main()
{
int line = __LINE__; //注意:LINE前后分别是两个下划线“_”(半角状态下)
string file = __FILE__;
cout<<line<<endl;
cout<<file<<endl;
}
//C语言
void main()
{
int line = __LINE__;
char * file = __FILE__;
printf("%d\n", line);
printf("%s\n", file);
}
int main()
{
int line = __LINE__; //注意:LINE前后分别是两个下划线“_”(半角状态下)
string file = __FILE__;
cout<<line<<endl;
cout<<file<<endl;
}
//C语言
void main()
{
int line = __LINE__;
char * file = __FILE__;
printf("%d\n", line);
printf("%s\n", file);
}
4,两个数相乘,小数点后位数没有限制,请写一个高精度算法
这个算法思路比较容易,就是高精度的大整数相乘,但是要考虑小数点的位置。
假设记作a,b两个数字。分别存放到两个数组A,B中去,不考虑小数点。并且记录a, b小数点后分别有多少位记作:m, n。
然后将数组A, B按照大整数相乘的方法得到一个乘积存放在数组C中,C的长度是A,B长度之和。然后小数点位置就在倒数第m+n位置上。
这个只是答题思路,具体细节还要分外考虑。
5,写一个病毒
这个。。不知道病毒的定义是什么样子的。。你写一个程序,只要运行就不停的进行读写操作占用CPU和内存,而且删除系统文件,这个算是病毒吗??
我以前写过一个脚本修改注册表的,你把下面的代码拷贝到txt中,然后将后缀名改成reg点击试试,不知道win7下如何,xp屡试不爽。
REGEDIT4
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Folder\Hidden\SHOWALL]
"CheckedValue"=dword:00000000
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]
"DisableTaskMgr"=dword:00000001
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]
"DisableRegistryTools"=dword:00000001
这三个语句分别是禁止显示隐藏文件,禁用任务管理器以及禁用注册表。。然后俺就可以肆意的搞你了,这个挺无语的吧。修复方法:
REGEDIT4
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Folder\Hidden\SHOWALL]
"CheckedValue"=dword:00000001
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]
"DisableTaskMgr"=dword:00000000
6,不使用额外空间,将 A, B两链表的元素交叉归并
既然是链表,交换交换指针不就行了吗??没看出这题的难点,求高人指点。
我们假设不知道长度的情况下,将list2归并到list1,伪代码如下:
//伪代码
PNode p1 = plist1, p2 = plist2, tmp1, tmp2;
while(p1->next != NULL && p2->next != NULL)
{
tmp1 = p1->next;
tmp2 = p2->next;
p1->next = p2;
p2->next = tmp1;
p2 = tmp2;
p1 = tmp1;
}
if(p1->next == NULL && p2->next != NULL)
p1->next = p2;
return p1;
PNode p1 = plist1, p2 = plist2, tmp1, tmp2;
while(p1->next != NULL && p2->next != NULL)
{
tmp1 = p1->next;
tmp2 = p2->next;
p1->next = p2;
p2->next = tmp1;
p2 = tmp2;
p1 = tmp1;
}
if(p1->next == NULL && p2->next != NULL)
p1->next = p2;
return p1;
7,MFC 将树序列化 转存在数组或 链表中。
所谓序列化就是一种永久保存,一般就是将对象保存到一个文件中去,然后读取这个文件又可以完全得到原本的对象数据结构信息。
对于树的结构,是一种层次关系,这正好可以对应于xml文件。我们可以把树结构写进xml文件中去。
http://www.codeproject.com/KB/tree/ctreectrl_xml.aspx 给出了这种方法的实现。
就是对xml定一个规则,节点的层次用一个属性level来表示,例如 <Node level= "1 "> value </Node>。
在保存的时候,遍历TreeCtrl的节点,使用DOM方式动态的生成XML的节点,最后保存为xml文件。
在从xml文件中读取的时候,可以使用SAX的方式,根据level属性的值,动态的确定父子关系。
8,计算 a^b << 2 (运算符优先级问题)
<<运算优先级高于^
9,根据二叉树的先序,中序遍历求后序遍历
先根据先序我们得出整个树的根,然后在中序遍历中查找根所出现的位置(如果找不到这个根就是序列不合理的情况了),在中序应遍历中出现的根的左边的一定是树的左子树的结点,出现在右边的一定是右子树的结点,然后我们根据树的遍历规律可以在先序遍历中找到左子树的结点与右子树的结点,这样我们就而对了一个重复性的问题,就是已知先序与中序遍历构建树,递归便可以构建出整个树。
10,写出socks套接字 服务端 客户端 通讯程序
我就把我的毕设的一个基于异步选择IO模式的网络监控程序的部分代码贴一下把。注意这是基于异步非阻塞模式的。
客户端:
//初始化套接字
bool CNetClientDlg::InitSocket()
{
m_socket = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, 0);
if(INVALID_SOCKET == m_socket)
{
MessageBox(_T("创建套接字失败!"));
return false;
}
SOCKADDR_IN addrSock;
addrSock.sin_family = AF_INET;
addrSock.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSock.sin_port = htons(CLIENT_PORT);
if(bind(m_socket, (SOCKADDR*)&addrSock, sizeof(SOCKADDR)) == SOCKET_ERROR)
{
MessageBox(_T("绑定失败!"));
return false;
}
if(WSAAsyncSelect(m_socket, m_hWnd, UM_SOCK, FD_READ | FD_CLOSE) == SOCKET_ERROR)
{
MessageBox(_T("注册网络事件失败!"));
return false;
}
return true;
}
//自定义消息
// SOCK消息
#define UM_SOCK WM_USER+1
//消息映射
ON_MESSAGE(UM_SOCK, OnSock)
//UM_SOCK的消息相应代码的实现
//wParam标识已经发生网络事件的套接字
//lParam的低位字标识已经发生的那个网络事件,高位子标识错误信息
LRESULT CNetClientDlg::OnSock(WPARAM wParam, LPARAM lParam)
{
switch(LOWORD(lParam))
{
case FD_CLOSE:
MessageBox(_T("服务器中断连接!"));
break;
case FD_READ:
{
WSABUF wsabuf;
//注意是动态分配的
wsabuf.buf = new char[200];
wsabuf.len = 200;
DWORD dwRead;
DWORD dwFlag = 0;
SOCKADDR_IN addrFrom;
int len = sizeof(SOCKADDR);
if(WSARecvFrom(m_socket, &wsabuf, 1, &dwRead, &dwFlag, (SOCKADDR*)&addrFrom, &len, NULL, NULL)
== SOCKET_ERROR)
{
KillTimer(TIMER_SPEED_NUM);
MessageBox(_T("接收数据失败!服务器端可能已经中断连接"));
delete[] wsabuf.buf;
return 0;
}
switch (wsabuf.buf[0])
{
//如果是响应的注册信息
case 'R':
{
//注册成功
if(wsabuf.buf[1] == 'S')
{
MessageBox(_T("注册成功!"));
}
else
{
MessageBox(_T("注册失败!请更换用户名!"));
}
break;
}
//如果是响应的登陆信息
case 'L':
{
//登陆成功
if(wsabuf.buf[1] == 'S')
{
MessageBox(_T("登陆成功!"));
isLogin = true;
trafficInfo.userID = logInfo.userID;
trafficInfo.dwIP = logInfo.dwIP;
SetTimer(TIMER_SPEED_NUM, TIMER_SPEED_LAG, NULL);
toTray();
}
else
{
MessageBox(_T("登陆失败!用户名或者密码不正确或此帐户已经登录!"));
}
break;
}
//服务器退出
case 'Q':
{
KillTimer(TIMER_SPEED_NUM);
break;
}
default:
break;
}
delete[] wsabuf.buf;
break;
}
default:
break;
}
return 0;
}
bool CNetClientDlg::InitSocket()
{
m_socket = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, 0);
if(INVALID_SOCKET == m_socket)
{
MessageBox(_T("创建套接字失败!"));
return false;
}
SOCKADDR_IN addrSock;
addrSock.sin_family = AF_INET;
addrSock.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSock.sin_port = htons(CLIENT_PORT);
if(bind(m_socket, (SOCKADDR*)&addrSock, sizeof(SOCKADDR)) == SOCKET_ERROR)
{
MessageBox(_T("绑定失败!"));
return false;
}
if(WSAAsyncSelect(m_socket, m_hWnd, UM_SOCK, FD_READ | FD_CLOSE) == SOCKET_ERROR)
{
MessageBox(_T("注册网络事件失败!"));
return false;
}
return true;
}
//自定义消息
// SOCK消息
#define UM_SOCK WM_USER+1
//消息映射
ON_MESSAGE(UM_SOCK, OnSock)
//UM_SOCK的消息相应代码的实现
//wParam标识已经发生网络事件的套接字
//lParam的低位字标识已经发生的那个网络事件,高位子标识错误信息
LRESULT CNetClientDlg::OnSock(WPARAM wParam, LPARAM lParam)
{
switch(LOWORD(lParam))
{
case FD_CLOSE:
MessageBox(_T("服务器中断连接!"));
break;
case FD_READ:
{
WSABUF wsabuf;
//注意是动态分配的
wsabuf.buf = new char[200];
wsabuf.len = 200;
DWORD dwRead;
DWORD dwFlag = 0;
SOCKADDR_IN addrFrom;
int len = sizeof(SOCKADDR);
if(WSARecvFrom(m_socket, &wsabuf, 1, &dwRead, &dwFlag, (SOCKADDR*)&addrFrom, &len, NULL, NULL)
== SOCKET_ERROR)
{
KillTimer(TIMER_SPEED_NUM);
MessageBox(_T("接收数据失败!服务器端可能已经中断连接"));
delete[] wsabuf.buf;
return 0;
}
switch (wsabuf.buf[0])
{
//如果是响应的注册信息
case 'R':
{
//注册成功
if(wsabuf.buf[1] == 'S')
{
MessageBox(_T("注册成功!"));
}
else
{
MessageBox(_T("注册失败!请更换用户名!"));
}
break;
}
//如果是响应的登陆信息
case 'L':
{
//登陆成功
if(wsabuf.buf[1] == 'S')
{
MessageBox(_T("登陆成功!"));
isLogin = true;
trafficInfo.userID = logInfo.userID;
trafficInfo.dwIP = logInfo.dwIP;
SetTimer(TIMER_SPEED_NUM, TIMER_SPEED_LAG, NULL);
toTray();
}
else
{
MessageBox(_T("登陆失败!用户名或者密码不正确或此帐户已经登录!"));
}
break;
}
//服务器退出
case 'Q':
{
KillTimer(TIMER_SPEED_NUM);
break;
}
default:
break;
}
delete[] wsabuf.buf;
break;
}
default:
break;
}
return 0;
}
服务器端:
//初始化套接字
bool CNetMonitorDlg::InitSocket()
{
m_socket = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, 0);
if(INVALID_SOCKET == m_socket)
{
MessageBox(_T("创建套接字失败!"));
return false;
}
SOCKADDR_IN addrSock;
addrSock.sin_family = AF_INET;
addrSock.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSock.sin_port = htons(SERVER_PORT);
if(bind(m_socket, (SOCKADDR*)&addrSock, sizeof(SOCKADDR)) == SOCKET_ERROR)
{
MessageBox(_T("绑定失败!"));
return false;
}
if(WSAAsyncSelect(m_socket, m_hWnd, UM_SOCK, FD_READ | FD_CONNECT | FD_CLOSE) == SOCKET_ERROR)
{
MessageBox(_T("注册网络事件失败!"));
return false;
}
return true;
}
//UM_SOCK的消息相应代码的实现
//wParam标识已经发生网络事件的套接字
//lParam的低位字标识已经发生的那个网络事件,高位子标识错误信息
LRESULT CNetMonitorDlg::OnSock(WPARAM wParam, LPARAM lParam)
{
switch(LOWORD(lParam))
{
case FD_CONNECT:
MessageBox(_T("连接成功!"));
break;
case FD_CLOSE:
MessageBox(_T("客户端中断连接!"));
break;
case FD_READ:
{
WSABUF wsabuf;
//注意是动态分配的
wsabuf.buf = new char[200];
wsabuf.len = 200;
DWORD dwRead;
DWORD dwFlag = 0;
SOCKADDR_IN addrFrom;
int len = sizeof(SOCKADDR);
if(WSARecvFrom(m_socket, &wsabuf, 1, &dwRead, &dwFlag, (SOCKADDR*)&addrFrom, &len, NULL, NULL)
== SOCKET_ERROR)
{
MessageBox(_T("接收数据失败!"));
delete[] wsabuf.buf;
return 0;
}
//判断接收端是什么信息
switch (wsabuf.buf[0])
{
//如果是注册信息
case 'R':
{
CString strRecv(wsabuf.buf);
RegisterInfo m_reg(strRecv, addrFrom);
if(!m_reg.sendResult(&m_socket))
MessageBox(_T("用户") + m_reg.userID + _T("的注册结果回送失败!"));
if(m_reg.isSuccess)
{
TCItem.hParent = hCur2;
TCItem.item.pszText = m_reg.userID.GetBuffer();
TCItem.item.lParam = index2++; //子项序号
m_treeCtrl.InsertItem(&TCItem);
m_treeCtrl.Expand(hCur1,TVE_EXPAND); //展开树
m_strArrayUserID.Add(m_reg.userID);
m_strArrayAddress.Add(m_reg.userAddress);
userCount++;
MessageBox(_T("用户") + m_reg.userID + _T("成功注册!"));
}
break;
}
//如果是登录信息
case 'L':
{
CString strRecv(wsabuf.buf);
LoginInfo m_login(strRecv, addrFrom);
//此帐户已经登陆了
if(m_mapUserInfo.count(m_login.userID) > 0)
m_login.isSuccess = false;
if(!m_login.sendResult(&m_socket))
MessageBox(_T("用户") + m_login.userID + _T("的登陆结果回送失败!"));
if(m_login.isSuccess)
{
UserInfo userInfo(m_login.userID, m_login.userIP);
userInfo.cpuInfo = m_login.cpuInfo;
userInfo.ramInfo = m_login.ramInfo;
userInfo.hostName = m_login.hostName;
for(int i = 0; i < m_strArrayUserID.GetSize(); i++)
{
if(m_strArrayUserID[i] == m_login.userID)
{
userInfo.userAddress = m_strArrayAddress[i];
break;
}
}
m_mapUserInfo.insert(pair<CString, UserInfo>(userInfo.userID, userInfo));
TCItem.hParent = hCur1;
TCItem.item.pszText = userInfo.userID.GetBuffer();
TCItem.item.lParam = index1++;//子项序号
m_treeCtrl.InsertItem(&TCItem);
m_treeCtrl.Expand(hCur1,TVE_EXPAND);//展开树
m_login.storeInDatabase();
MessageBox(_T("用户") + m_login.userID + _T("已登录!"));
}
break;
}
//如果是速度和CPU使用率的信息
case 'S':
{
CString strRecv(wsabuf.buf);
TrafficInfo trafficInfo(strRecv, addrFrom);
trafficInfo.upSpeed = trafficInfo.getUpSpeed();
m_mapUserInfo[trafficInfo.userID].upSpeed = trafficInfo.upSpeed;
m_mapUserInfo[trafficInfo.userID].downSpeed = trafficInfo.downSpeed;
m_mapUserInfo[trafficInfo.userID].cpuUse = trafficInfo.cpuUse;
break;
}
//如果是某个客户端中断连接
case 'Q':
{
/*************************************************************************************
网络流量信息数据格式:_T("Q#") + userID + _T("$");
例如:"Q#MyName$"
*************************************************************************************/
CString strRecv(wsabuf.buf);
int i = 2, j;
j = strRecv.Find('$', i);
CString userID = strRecv.Mid(i, j-i);
//从在线用户中查找树节点
HTREEITEM hCur = treeFindItem(hCur1, userID);
if (hCur != NULL)
{
//将此节点删除
m_treeCtrl.DeleteItem(hCur);
m_treeCtrl.UpdateData(false);
m_mapUserInfo.erase(userID);
MessageBox(_T("用户") + userID + _T("已退出!"));
}
break;
}
default:
break;
}
delete[] wsabuf.buf;
break;
}
default:
break;
}
return 0;
}
bool CNetMonitorDlg::InitSocket()
{
m_socket = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, 0);
if(INVALID_SOCKET == m_socket)
{
MessageBox(_T("创建套接字失败!"));
return false;
}
SOCKADDR_IN addrSock;
addrSock.sin_family = AF_INET;
addrSock.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSock.sin_port = htons(SERVER_PORT);
if(bind(m_socket, (SOCKADDR*)&addrSock, sizeof(SOCKADDR)) == SOCKET_ERROR)
{
MessageBox(_T("绑定失败!"));
return false;
}
if(WSAAsyncSelect(m_socket, m_hWnd, UM_SOCK, FD_READ | FD_CONNECT | FD_CLOSE) == SOCKET_ERROR)
{
MessageBox(_T("注册网络事件失败!"));
return false;
}
return true;
}
//UM_SOCK的消息相应代码的实现
//wParam标识已经发生网络事件的套接字
//lParam的低位字标识已经发生的那个网络事件,高位子标识错误信息
LRESULT CNetMonitorDlg::OnSock(WPARAM wParam, LPARAM lParam)
{
switch(LOWORD(lParam))
{
case FD_CONNECT:
MessageBox(_T("连接成功!"));
break;
case FD_CLOSE:
MessageBox(_T("客户端中断连接!"));
break;
case FD_READ:
{
WSABUF wsabuf;
//注意是动态分配的
wsabuf.buf = new char[200];
wsabuf.len = 200;
DWORD dwRead;
DWORD dwFlag = 0;
SOCKADDR_IN addrFrom;
int len = sizeof(SOCKADDR);
if(WSARecvFrom(m_socket, &wsabuf, 1, &dwRead, &dwFlag, (SOCKADDR*)&addrFrom, &len, NULL, NULL)
== SOCKET_ERROR)
{
MessageBox(_T("接收数据失败!"));
delete[] wsabuf.buf;
return 0;
}
//判断接收端是什么信息
switch (wsabuf.buf[0])
{
//如果是注册信息
case 'R':
{
CString strRecv(wsabuf.buf);
RegisterInfo m_reg(strRecv, addrFrom);
if(!m_reg.sendResult(&m_socket))
MessageBox(_T("用户") + m_reg.userID + _T("的注册结果回送失败!"));
if(m_reg.isSuccess)
{
TCItem.hParent = hCur2;
TCItem.item.pszText = m_reg.userID.GetBuffer();
TCItem.item.lParam = index2++; //子项序号
m_treeCtrl.InsertItem(&TCItem);
m_treeCtrl.Expand(hCur1,TVE_EXPAND); //展开树
m_strArrayUserID.Add(m_reg.userID);
m_strArrayAddress.Add(m_reg.userAddress);
userCount++;
MessageBox(_T("用户") + m_reg.userID + _T("成功注册!"));
}
break;
}
//如果是登录信息
case 'L':
{
CString strRecv(wsabuf.buf);
LoginInfo m_login(strRecv, addrFrom);
//此帐户已经登陆了
if(m_mapUserInfo.count(m_login.userID) > 0)
m_login.isSuccess = false;
if(!m_login.sendResult(&m_socket))
MessageBox(_T("用户") + m_login.userID + _T("的登陆结果回送失败!"));
if(m_login.isSuccess)
{
UserInfo userInfo(m_login.userID, m_login.userIP);
userInfo.cpuInfo = m_login.cpuInfo;
userInfo.ramInfo = m_login.ramInfo;
userInfo.hostName = m_login.hostName;
for(int i = 0; i < m_strArrayUserID.GetSize(); i++)
{
if(m_strArrayUserID[i] == m_login.userID)
{
userInfo.userAddress = m_strArrayAddress[i];
break;
}
}
m_mapUserInfo.insert(pair<CString, UserInfo>(userInfo.userID, userInfo));
TCItem.hParent = hCur1;
TCItem.item.pszText = userInfo.userID.GetBuffer();
TCItem.item.lParam = index1++;//子项序号
m_treeCtrl.InsertItem(&TCItem);
m_treeCtrl.Expand(hCur1,TVE_EXPAND);//展开树
m_login.storeInDatabase();
MessageBox(_T("用户") + m_login.userID + _T("已登录!"));
}
break;
}
//如果是速度和CPU使用率的信息
case 'S':
{
CString strRecv(wsabuf.buf);
TrafficInfo trafficInfo(strRecv, addrFrom);
trafficInfo.upSpeed = trafficInfo.getUpSpeed();
m_mapUserInfo[trafficInfo.userID].upSpeed = trafficInfo.upSpeed;
m_mapUserInfo[trafficInfo.userID].downSpeed = trafficInfo.downSpeed;
m_mapUserInfo[trafficInfo.userID].cpuUse = trafficInfo.cpuUse;
break;
}
//如果是某个客户端中断连接
case 'Q':
{
/*************************************************************************************
网络流量信息数据格式:_T("Q#") + userID + _T("$");
例如:"Q#MyName$"
*************************************************************************************/
CString strRecv(wsabuf.buf);
int i = 2, j;
j = strRecv.Find('$', i);
CString userID = strRecv.Mid(i, j-i);
//从在线用户中查找树节点
HTREEITEM hCur = treeFindItem(hCur1, userID);
if (hCur != NULL)
{
//将此节点删除
m_treeCtrl.DeleteItem(hCur);
m_treeCtrl.UpdateData(false);
m_mapUserInfo.erase(userID);
MessageBox(_T("用户") + userID + _T("已退出!"));
}
break;
}
default:
break;
}
delete[] wsabuf.buf;
break;
}
default:
break;
}
return 0;
}