高分求解封包问题

pbdwadr 2010-04-19 02:56:13
小弟初学Winsock
想了解下用SOCKET发送数据的时候如何封包呢?

问题1:
我可以这样发送吗?
封装一个结构体:
struct a
{
char filename[MAX_PATH];
UINT count;
char* dataArray;
};

然后用send发送的时候,强制把struct a转换成char*发送,可以吗?
a aa;
send((char*)&aa, size, ..);

问题2:
如果filename中有中文,会不会出现乱码?

问题3:
一般最好要如何定义发送包的格式?

希望大家多多指点!谢谢!!
...全文
213 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
goright 2010-04-20
  • 打赏
  • 举报
回复
顶一下,楼上回答的都不错
whs1980 2010-04-20
  • 打赏
  • 举报
回复
楼上已经说的很明白了,你要把所有内容都放到一个连续的,指定大小尺寸的内存块以后才能发送,套接字不会自动根据你的指针去把要发的内容都找出来,然后再发送的.
一般的处理是在内存里把这些变长的内容序列化,然后再接收的时候反序列化.
pbdwadr 2010-04-20
  • 打赏
  • 举报
回复
其实我的代码大概是这样的,大家帮忙看看有什么问题。谢谢!
send的时候老是有10014错误

struct SBRIEF
{
char cmd; // 要干什么
UINT unBytes; // 后面要发送的数据有多少字节
};

struct SDIRFILE
{
wchar_t szName[MAX_PATH]; // 目录/文件名
bool bDir; // 是否是目录
};

struct SPUTDIRLIST
{
char szDirPath[MAX_PATH]; // 新数据所属的目录路径
UINT uCount; // 新数据的记录条数
SDIRFILE* pDirFileArray; // 新数据的记录数组
};

struct STHREADPUTDIRLIST
{
SBRIEF brief;
SPUTDIRLIST putDirList;
};

// 首先,准备好欲发送的数据
CString strPath(TEXT(""));
SDIRFILE* pDirFileArrayTmp = g_dirSys.GetDirFileArray(strPath);
int nCount = g_dirSys.GetArrayElemCount();

// 拷贝到新的缓存,防止被多线程修改
SDIRFILE* pDirFileArray = new SDIRFILE[nCount];
for(int i=0; i<nCount; ++i)
{
pDirFileArray[i].bDir = pDirFileArrayTmp[i].bDir;
wcscpy(pDirFileArray[i].szName, pDirFileArrayTmp[i].szName);
}

// 这里本来是构建结构体,令启动一个发送线程发送的,为了简化描述,直接在本线程发送
STHREADPUTDIRLIST* lpParameter = new STHREADPUTDIRLIST;
lpParameter->brief.cmd = CMD_PUT_DIR_LIST;
lpParameter->brief.unBytes = sizeof(SDIRFILE)*nCount+sizeof(UINT)+MAX_PATH;
lpParameter->putDirList.uCount = nCount;
strcpy(lpParameter->putDirList.szDirPath, "");
lpParameter->putDirList.pDirFileArray = pDirFileArray;

SBRIEF* pBf = &(((STHREADPUTDIRLIST*)lpParameter)->brief);
SPUTDIRLIST* pPdl = &(((STHREADPUTDIRLIST*)lpParameter)->putDirList);

if( !g_tcpSock.Send((char*)pBf, sizeof(SBRIEF)) )
{
cout << "send error!" << endl;
}

// 在这里老是有10014错误,MSDN上解释:The buf parameter is not completely contained in a valid part of the user address space.
if( !g_tcpSock.Send((char*)pPdl, pBf->unBytes) )
{
cout << "send error!" << endl;
}
dns007 2010-04-20
  • 打赏
  • 举报
回复
mark 帮顶!!
whs1980 2010-04-20
  • 打赏
  • 举报
回复
问题1:
我可以这样发送吗?
封装一个结构体:
struct a
{
char filename[MAX_PATH];
UINT count;
char* dataArray;
};

然后用send发送的时候,强制把struct a转换成char*发送,可以吗?
a aa;
send((char*)&aa, size, ..);
//这样发送是不行的,因为你获取到的size只是结构体的尺寸只包含了指针的长度(4个字节),而没有包含dataArray中的内容,就算这样发到客户端或者服务器端,也无法给你解析出正确的内容.char* dataArray;必须改成一个字符串数组.并且在另外一端要用同样的结构体去做类型转换.


问题2:
如果filename中有中文,会不会出现乱码?
//如果你用的与发送相同方式去接收数据,不会出现乱码,不管你用的是ANSI还是UNICODE.

问题3:
一般最好要如何定义发送包的格式?
最好的包格式:固定头+可变长度内容.
固定头中包含可变长度内容的长度,
即发送包的时候,先发送一个固定尺寸的消息头,指定接下来要传送数据的大小,然后再按指定的大小去接收数据,是最好的.
尹成 2010-04-20
  • 打赏
  • 举报
回复
结构体中的dataArray成员最好写成数组,另外建议使用uncode,否则肯定乱码
cnzdgs 2010-04-19
  • 打赏
  • 举报
回复
1、这样发送是可以,但指针只能在本进程中使用,发送指针没有意义,接收放无法利用指针获取数据。
2、只要双方使用相同的字符集就没有问题。
3、
这样定义结构:
struct a
{
char filename[MAX_PATH];
UINT datalength;
};
先发送结构,再接着发送数据,接收方先接收结构,再根据结构中记录的数据长度来接收文件数据。
kkmqj 2010-04-19
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 visualeleven 的回复:]

结构体中的dataArray成员最好写成数组形式会比较好一些。。。
[/Quote]
同意这个
这不是鸭头 2010-04-19
  • 打赏
  • 举报
回复
muyiyj 2010-04-19
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 bragi523 的回复:]
1.你这样的包球长度的时候不能用sizeof求得,一般都用char dataArray[4096];的形式
然后分包发送
2.乱码是不会出现,只要你发过去再转成unicode的
3.给你哥封包建议
struct a
{
UINT type; //数据类型(比如文件名为1,文件数据为2)
UINT count;//每个包的长度
char dataArray[4096];
};
这……
[/Quote]

说得很好哈,以前我也是自己定义私有格式(就是自己定义个结构体),然后通过socket发送出去的,接收方根据接收的内容,强制还原成原来的结构体就可以了
bragi523 2010-04-19
  • 打赏
  • 举报
回复
1.你这样的包球长度的时候不能用sizeof求得,一般都用char dataArray[4096];的形式
然后分包发送
2.乱码是不会出现,只要你发过去再转成unicode的
3.给你哥封包建议
struct a
{
UINT type; //数据类型(比如文件名为1,文件数据为2)
UINT count;//每个包的长度
char dataArray[4096];
};
这样文件名也单独发送,
或者你也可以把文件名和长度封成struct复制到dataArray地址发送
zhanshen2891 2010-04-19
  • 打赏
  • 举报
回复
当然可以发送了
Eleven 2010-04-19
  • 打赏
  • 举报
回复
结构体中的dataArray成员最好写成数组形式会比较好一些。。。

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧