如果客户端发送的一条消息数据是一定格式的,例如:消息头+消息内容长度+内容.客户端每隔一秒就发送一次.
实际中发现客户端发送消息到服务端,服务端每次接收的数据,有些是完整的,但有些只有消息头+消息内容长度+一半的内容,或者就只有一半的内容,也有些是接收的数据是几条消息并在一起的.有什么办法能让数据能让数据完整的接收呢,或是有什么办法在接收到这些残缺的消息后做处理可以让消息完整?另外,为何一次接收会有多条消息并在一起呢???
实际中发现客户端发送消息到服务端,服务端每次接收的数据,有些是完整的,但有些只有消息头+消息内容长度+一半的内容,或者就只有一半的内容,也有些是接收的数据是几条消息并在一起的.有什么办法能让数据能让数据完整的接收呢,或是有什么办法在接收到这些残缺的消息后做处理可以让消息完整?另外,为何一次接收会有多条消息并在一起呢???
解决方案 »
- 问个三层的问题,在应用层ADOQuery中写SQL语句,与在客户端ClientDataSet中写SQL语有什么区别没有?
- c/s中的客户端查询问题??
- 怎样将输入的字符串转储到数组里?
- 在使用rmreport控件时,如何控制走纸
- 有关word文件打印的问题,up有分
- rational rose 可不可以给delphi建模?我装了一个,好像不行。
- 如何实现Toolbar不够长的时候右边自动出来一个下拉按钮,并把隐藏的按钮项目放到菜单里面?
- listbox.moveselection怎么用?
- 100分请教。BusinessSkinForm 控件,如何更改窗口标题的字体?
- 如何更改颜色
- hwnd转换问题
- stringgrid的case后可否执行多条语句
var
Len: Integer; //消息长度(或者是Word,或者是Byte,看自己怎么定义)
S, sTemp: string; //收到的消息
AHead: THead; //自定义的消息头结构
begin
while Length(S) > (SizeOf(THead) + SizeOf(Integer)) do
begin
Move(S[1], AHead, SizeOf(THead)); //读取消息头
Delete(S, 1, SizeOf(THead)); //删除消息头
Move(S[1], Len, SizeOf(Integer)); //读取消息长度
Delete(S, 1, SizeOf(Integer)); //删除消息长度
sTemp := Copy(S, 1, Len); //读取消息
Delete(S, 1, Len); //删除消息
end;//while
//其他处理
if S <> '' then
begin
//这个是没有接收完的包...
end;//if
//...
发送的时候是一包一包发送的,接收不一定,可能一次接收了几个小的数据包,也可能几次接收一个大的数据包。
可以这样解决:
开辟一个缓冲区,每次接收数据后,都把数据追加到缓冲区中,缓冲区可以是一个队列的处理方式,然后判断缓冲区里是否有完整的数据包,通过自定义的结构来判断,消息头+消息内容长度+消息内容,有就处理,处理后把处理过的数据清掉,没有就继续等待接收。
buf.buf = recvbuff;
buf.len = datalen;
WSARecv(s, buf, 1, ...);也就是说告诉 WSARecv:这一次的接收最大只接受这么多数据,多出来的那部分数据就让它留在系统缓冲区中。另一方面,有时候 datalen 比较大,不能一次传输完成的情况下,就需要进行消息拼接,如:class CRecvBuff
{
public:
char *m_lpBuff;
int m_nBuffSize;
WSABUF wsabuf;public:
CRecvBuff(int nBuffSize)
{
m_lpBuff = new char[nBuffSize];
m_nBuffSize = nBuffSize;
wsabuf.buf = m_lpBuff;
wsabuf.len = nBuffSize;
}
};void OnRecv(DWORD dwError, DWORD cbTransferred, CRecvBuff *buf)
{
// 递增缓冲区
buff->wsabuf.buf += cbTransferred; // 递减缓冲区长度
buff->wsabuf.len -= cbTransferred;
if (buff.len > 0)
{
// 此消息仍有数据未接收完,再次调用 WSARecv 接收剩下的数据
WSARecv(s, &buf->wsabuf, 1, ...);
}
else
{
// 消息数据已经完成接收
OnPacketRecvd(...);
}
}