观察文件
获取server端电脑里面存在哪些盘符
int MakeDriveInfo() { //1==>A 2==>B (原本属于软盘的 )3==>C ... 26==>Z
std::string result;
for (int i = 1; i < 26; i++) { //让其循环
if (_chdrive(i) == 0) //改变当前的驱动,_chdrive函数(c和c++中)应该是封装了win的api函数GetLogicalDrives(说反了)
{
if (result.size() > 0) {
result += ',';
}
result += 'A' + i - 1;
//切换成功
}
}
CPacket pack(1, (BYTE*)result.c_str(), result.size()); //重载了构造函数(如果不重载成员变量需要一个个值赋值太麻烦了),打包用的,抽象
Dump((BYTE*)pack.Data(), pack.Size()); //自己控制台输出打包数据(debug)
//CserverSocket::getInstance()->Send(pack);
return 0;
}
我们之前的构造函数只有解包的操作,没有打包的操作,打包发到client端的操作
新加一个构造函数
//下面是打包的操作
CPacket(WORD nCmd, const BYTE* pData, size_t nSize) { //常量指针,指向的内容不能改变
sHead = 0xFEFF; //头
nLength = nSize + 2 + 2; //数据的长度加上命令长度加上校验的长度
sCmd = nCmd; //命令
if (nSize > 0) { //有数据
strData.resize(nSize); //给包data容器重新设置长度
memcpy((void*)strData.c_str(), pData, nSize); //给包打他字段设置上
}
else { //没有数据了,头字段和命令字段要清空
strData.clear();
}
sSum = 0; //校验和
for (size_t j = 0; j < strData.size(); j++) {
sSum += BYTE(strData[j]) & 0xFF;
} //添加校验和
}
打包了就是Send函数,之前写的Send函数同样需要重载(这是给客户端送数据,所以直接是packet)
bool Send(const CPacket& pack) {
if (m_client == -1) return false;
return send(m_client, (const char*)&pack, pack.nLength+2+4, 0) > 0;
}
谁来调用这个Send,当然是pserver
但是我们程序没有写好,需要一个测试函数,自己构造的这个包里面的信息能不能成功打印出来
void Dump(BYTE* pData, size_t nSize) {
std::string strOut;
for (size_t i = 0; i < nSize; i++) {
char buf[8] = "";//缓冲区,把二进制的0/1当char一个字节来存入(质疑)
if (i > 0 && (i % 16 == 0)) strOut += "\n"; //每隔16位补0
snprintf(buf, sizeof(buf), "%02X ", pData[i] & 0xFF); //按16进制输出,不足两位补0,与上ff的原因是byte转成int过程中,负数的话前面补1,影响结果
strOut += buf;
}
strOut += "\n";
OutputDebugStringA(strOut.c_str());
}
这个Dump函数模拟的是客户端输出的情况,所以就两个值一个是这一个数据包的完整数据(模拟的暂时还不支持解包),和长度
所以还要另外写函数,来返回pack完整内容Data()还有Size()
测试发现
FFFE CCCC 0500 0000 0100 CC
这个地方多了cc是WORD对齐导致的
解决方法如下:
//ServerSocket.h
#pragma pack(push)
#pragma pack(1)
class CPacket
{
```
```
```
};
#pragma pack(pop)
加上以后的结果:
FFFE 05000000 0100 E0 210C
发现盘符那个位置是E0转ASCII码不是C盘
下一个断点看了看
没毛病,确实是C盘
但是strData是对象,取对象的地址,肯定并不会得到对象的值
string是对象,相当于对象中有个对象,对外层的对象传地址再取值,到里层对象那里是地址
有一个人解释的很清楚
自己多次运行
发现后面那个data部分是在变的,印证猜想
解决方法
让自己的包自带一个缓冲区,在packet成员变量里面加上
std::string strOut;//整个包的输出,这东西不用构造函数初始化
添加一个将packet有效数据添加到自身缓冲区的函数Data()
const char* Data() {
strOut.resize(nLength + 6);
BYTE* pData = (BYTE*)strOut.c_str();
*(WORD*)pData = sHead; pData += 2;
*(DWORD*)(pData) = nLength; pData += 4;
*(WORD*)pData = sCmd; pData += 2;
memcpy(pData, strData.c_str(), strData.size()); pData += strData.size();
*(WORD*)pData = sSum;
return strOut.c_str(); //c_str()接口是string类的一个函数,返回的是字符串的首地址,返回值类型是const char *的
}
16进制43转成ASCII就是C