Welcome>首页>随便写写>All>编程开发>SOCKET发送数据格式的那点事
37
SOCKET发送数据格式的那点事
文章分类:编程开发
发表日期:2010/04/22 21:04
总点击数:132
总评论数:0
前几天帮一MM做课程设计,要用到windows socket,之前没有学过windows socket编程,编程过程中遇到很多问题。

本文记录我遇到的socket发送数据包的格式问题。

代码简化如下:
struct SPERSON
{
	int nWeight;
	char szName;
};
struct STEAM
{
	int nCount;				// person的个数
    SPERSON* pPersonArray;	// SPERSON组成的数组指针
};

STEAM team;
team.nCount = 10;
team.pPersonArray = new SPERSON[team.nCount];
// 其他初始化操作省略
// ...
send(sock, (char*)&team, sizeof(STEAM)+team.nCount*sizeof(SPERSON));

这段代码有什么问题吗?
实际情况是:运行时send调用失败,返回错误码为10014MSDN上解释:The buf parameter is not completely contained in a valid part of the user address space.
为什么会出现这个问题呢?

原来是我犯了一个逻辑错误。
先看看send的原形:
int send(
  SOCKET s,
  const char FAR* buf,
  int len,
  int flags
);
Parameters
s 
[in] Descriptor identifying a connected socket. 
buf 
[in] Buffer containing the data to be transmitted. 
len 
[in] Length of the data in the buf parameter. 
flags 
[in] Indicator specifying the way in which the call is made. 
其实,send将从开始发送buf中的len字节数据。
这就说明buf中的数据在内存中要连续,否则就会发送错误的数据。

上面给出的代码刚好在这点犯了错误,teampPersonArraynew出来的,它的地址是不确定的,这就导致send发送的数据是错误的,尽管成功发送了正确的nCountpPersonArray指针(地址),但剩下发送的team.nCount*sizeof(SPERSON)字节数据是没有意义的数据,并不是辛辛苦苦new初来的那块。

那么,socket发送的数据要怎样封装呢?包的结构最好是什么样的?
我在CSDN上发帖求救,得到一些指点(帖子链接)。
结合自己的项目实践,总结如下:
最好先定义一个结构体,记录数据包的摘要性信息,最重要的是数据包的大小(字节)。
这样,当接收端收到并解析这个摘要信息后,就会知道数据包的具体字节。
然后,再发送数据包,千万注意,每次send的数据必须在内存上是连续的。
这样,就可以正确发送、接收、解析了。

到这里,修正上面给出的问题代码:
struct SPERSON
{
	int nWeight;
	char szName;
};
struct STEAMBRIEF
{
	int nCount;				// person的个数
};

STEAMBRIEF teamBrief;
teamBrief.nCount = 10;
SPERSON* pPersonArray = new SPERSON[teamBrief.nCount];
// 其他初始化操作省略
// ...

// 先发送摘要信息
send(sock, (char*)&teamBrief, sizeof(STEAMBRIEF));

// 再发送具体数据
send(sock, (char*)pPersonArray, teamBrief.nCount*sizeof(SPERSON));
客户端可以这么处理:
// 首先接收摘要信息
char* pBriefBuffer = new char[sizeof(STEAMBRIEF)];
recv(sock, pBriefBuffer, sizeof(STEAMBRIEF));

// 解析摘要信息
STEAMBRIEF* pBrief = (STEAMBRIEF*)pBriefBuffer;

// 接收真正数据
// person的个数
int nCount = pBrief->nCount;

char* pPersonArrayBuffer = new char[nCount*sizeof(SPERSON)];
recv(sock, pPersonArrayBuffer, nCount*sizeof(SPERSON));

SPERSON* pPersonArray = (SPERSON*)pPersonArrayBuffer;
解决了这个问题,后面的代码就很顺利了。
感觉socket也没什么大不了的,数据的传送和接收而已(呵呵,个人见解)。
感谢小妹妹给了我这次学习socket编程的机会。。。

2010-04-22 于 湖南长沙中南大学
请尊重版权,转载请注明出处;代码及文章如需用于商业用途需经本人同意
本文永久链接:http://www.outsky.org/article.php?action=read&category=1400&page=1&id=37