[IOCP]通过GetQueuedCompletionStatus()收到的网络包,如何判断是完整的包?

yrisxfyh 2015-02-09 09:09:58
GetQueuedCompletionStatus()只给了我重叠IO指针和传输的字节数,但我怎么判断它是一个完整的包呢?
比如先前我投递了1024个字节,可是收到的是100个节字,那么,我怎么判断这100个字节是完整的包还是不完整的?
...全文
448 38 打赏 收藏 转发到动态 举报
写回复
用AI写文章
38 条回复
切换为时间正序
请发表友善的回复…
发表回复
Sandrer 2015-02-13
  • 打赏
  • 举报
回复
[quote=引用 36 楼 yrisxfyh 的回复:] 我现在定义的包头是这样:

// 网络包头
struct SNPKHeader
{
	SNPKHeader(WORD mainMsg=0, WORD subMsg=0) : m_MainMsg(mainMsg), m_SubMsg(subMsg), m_Size(0) {}

	WORD	m_MainMsg;	// 主消息
	WORD	m_SubMsg;	// 子消息
	int		m_Size;		// 包数据大小(不包含SNPKHeader本身的大小)
};


// 恢复对齐状态
#pragma pack(pop)
我发现我们一直讨论的关键字有误区了......... “包”这个词是我们定义为通讯协议,里面包含有每个包所代表的含义 但其实我们要讨论的是如何确保网络发送的数据完整性,虽然tcp保证了数据的完整性,但它并不保证数据的结构性 它有可能会把一次发送的数据分成几次接收,也有可能把几次发送的数据合并成一次接收 那么我们要做的只是把每次发送的数据区分开来,而并不是说要把每个数据包区分开(数据包的处理当然是留给下级调用者了) 那么在每次数据发送前定义一个当前发送数据的大小我觉得很有必要 这样就可以告诉接收方我这次发送的数据大小是多少,无论你接收到多少数据,都要按照这个大小来区分每次的数据传输量 我#26楼所说类里面包含了包分析在内,其实是说在类里面处理接受的内容,把内容分成对方每次发送过来的数据大小
Sandrer 2015-02-13
  • 打赏
  • 举报
回复
引用 35 楼 yrisxfyh 的回复:
[quote=引用 34 楼 Sandrer 的回复:] [quote=引用 30 楼 yrisxfyh 的回复:] [quote=引用 25 楼 Sandrer 的回复:] [quote=引用 22 楼 yrisxfyh 的回复:] [quote=引用 21 楼 Sandrer 的回复:] 可以很负责的告诉你,你自己的包不写包头的话,系统是绝不会帮你做的 所有的通讯都是建立在“协议”上的,这个协议并不是 tcp、udp 这些底层网络协议 而是你自己定义的“交流”协议,你所传输的每个应用层数据包,都应该包含有一些简单的数据,例如包大小、包命令等等 不然服务端与客户端之间谁知道在传输什么东西,难道就只是传输1和0? 就算底层的tcp、udp这些网络协议,还不是都一样有包头?包头里面还不照样有包的大小在里面? 我就想不明白为什么一个简单的问题反而被你复杂化了,像你说的服务端不能做任何更改,但目前的情况是你不改不行
我在看大芒果的wow服务端代码,他用的是ACE网络库,我用IOCP给它发数据,他收到的就是原始的包,包头不记录包大小, 他就是一个字节一个字节在接收,第1个字节就是cmd,表明这个包的用途,根据cmd能知道这个包是什么包,进而确定大小,然后再recv之后的字节。 我最开始封装IOCP就是像你们所说的,包头一律包含4个字节记录包大小,但是我发现人家wow服务端就没有这些约束,所以感觉用4字节保存包大小真是不友好的设计[/quote] 估计你的源代码不对或者你表述得不清楚了 如果按照你说的方法,那怎么区分接收到的数据是否一个包呢? 如果服务器接收的数据被粘包了,你不可能循环所有数据每个字节来对比吧 肯定有一个标志位来区分每个数据包,因为你不知道你收到的数据的第一个字节,是否你发出的数据包,也有可能是被截断了的数据包[/quote] 我一直拿这个wow服务端源码进游戏调试,怎么能说源码不对呢。 我说的已经够详细了,他收到网络包后,先recv第1个字节cmd,根据这个cmd去判断是什么包,然后再recv之后的字节 [/quote] 问题是它怎么保证这个字节就是命令?如果接收到的数据是前一个包的后续数据体呢?[/quote] 那你怎么保证你第1个4字节就是包长度呢?[/quote] 这些没人可以保证,所以我说要自己在代码里去分析判断 举个例子: 客户端连接服务器,发送第一个数据包 那么这时服务端收到的第一个4字节数据就肯定是数据包大小 按照这个大小来处理后续的数据,如果这个包不是完整的,那么等待下个包 下个包到达,首先判断上一个包是否处理完毕,如果没处理则与当前包合并 然后根据上一个包的大小来截取相应长度的数据,把截取的数据分离 剩下的数据的第一个4字节为下一个包的大小,按照之前的做法继续循环下去 如果收到的包不足4字节,则等待下一个包到达、合并、处理 这里的包大小不一定是4字节,也可以是2字节或其它数目,这里只是打个比喻
Sandrer 2015-02-12
  • 打赏
  • 举报
回复
引用 30 楼 yrisxfyh 的回复:
[quote=引用 25 楼 Sandrer 的回复:] [quote=引用 22 楼 yrisxfyh 的回复:] [quote=引用 21 楼 Sandrer 的回复:] 可以很负责的告诉你,你自己的包不写包头的话,系统是绝不会帮你做的 所有的通讯都是建立在“协议”上的,这个协议并不是 tcp、udp 这些底层网络协议 而是你自己定义的“交流”协议,你所传输的每个应用层数据包,都应该包含有一些简单的数据,例如包大小、包命令等等 不然服务端与客户端之间谁知道在传输什么东西,难道就只是传输1和0? 就算底层的tcp、udp这些网络协议,还不是都一样有包头?包头里面还不照样有包的大小在里面? 我就想不明白为什么一个简单的问题反而被你复杂化了,像你说的服务端不能做任何更改,但目前的情况是你不改不行
我在看大芒果的wow服务端代码,他用的是ACE网络库,我用IOCP给它发数据,他收到的就是原始的包,包头不记录包大小, 他就是一个字节一个字节在接收,第1个字节就是cmd,表明这个包的用途,根据cmd能知道这个包是什么包,进而确定大小,然后再recv之后的字节。 我最开始封装IOCP就是像你们所说的,包头一律包含4个字节记录包大小,但是我发现人家wow服务端就没有这些约束,所以感觉用4字节保存包大小真是不友好的设计[/quote] 估计你的源代码不对或者你表述得不清楚了 如果按照你说的方法,那怎么区分接收到的数据是否一个包呢? 如果服务器接收的数据被粘包了,你不可能循环所有数据每个字节来对比吧 肯定有一个标志位来区分每个数据包,因为你不知道你收到的数据的第一个字节,是否你发出的数据包,也有可能是被截断了的数据包[/quote] 我一直拿这个wow服务端源码进游戏调试,怎么能说源码不对呢。 我说的已经够详细了,他收到网络包后,先recv第1个字节cmd,根据这个cmd去判断是什么包,然后再recv之后的字节 [/quote] 问题是它怎么保证这个字节就是命令?如果接收到的数据是前一个包的后续数据体呢?
Sandrer 2015-02-12
  • 打赏
  • 举报
回复
引用 28 楼 zhao4zhong1 的回复:
[quote=引用 27 楼 Sandrer 的回复:] [quote=引用 24 楼 zhao4zhong1 的回复:] 不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545
看了很多你回答的楼层,你一直都强调base64+\0结束符,问题是如果像你说的数据接收发生错误或者恶意攻击而发送垃圾数据的时候,这个\0终止符一直收不到的话怎么办?[/quote] 问题是如果像你说的数据接收发生错误或者恶意攻击而发送垃圾数据的时候,包长度被篡改的话怎么办?[/quote] 我觉得吧,无论数据包格式如何定义都难以避免错误接收或者而已删改的情况的,主要还是看服务端的分析来避免这情况 我的做法还是包头加数据长度,然后规定每个包的数据最大不能超过n字节,如果接收超过n字节数据的话,判断包无效,并且把该ip地址加入黑名单不允许再接收数据
yrisxfyh 2015-02-12
  • 打赏
  • 举报
回复
我现在定义的包头是这样:

// 网络包头
struct SNPKHeader
{
	SNPKHeader(WORD mainMsg=0, WORD subMsg=0) : m_MainMsg(mainMsg), m_SubMsg(subMsg), m_Size(0) {}

	WORD	m_MainMsg;	// 主消息
	WORD	m_SubMsg;	// 子消息
	int		m_Size;		// 包数据大小(不包含SNPKHeader本身的大小)
};


// 恢复对齐状态
#pragma pack(pop)
这个我包头是应用层定义的,IOCP封装类不会附加其它字节数据 当我投递recv收到结果后,我会先recv这个包头,然后再recv其中m_Size个字节数据
yrisxfyh 2015-02-12
  • 打赏
  • 举报
回复
引用 34 楼 Sandrer 的回复:
[quote=引用 30 楼 yrisxfyh 的回复:] [quote=引用 25 楼 Sandrer 的回复:] [quote=引用 22 楼 yrisxfyh 的回复:] [quote=引用 21 楼 Sandrer 的回复:] 可以很负责的告诉你,你自己的包不写包头的话,系统是绝不会帮你做的 所有的通讯都是建立在“协议”上的,这个协议并不是 tcp、udp 这些底层网络协议 而是你自己定义的“交流”协议,你所传输的每个应用层数据包,都应该包含有一些简单的数据,例如包大小、包命令等等 不然服务端与客户端之间谁知道在传输什么东西,难道就只是传输1和0? 就算底层的tcp、udp这些网络协议,还不是都一样有包头?包头里面还不照样有包的大小在里面? 我就想不明白为什么一个简单的问题反而被你复杂化了,像你说的服务端不能做任何更改,但目前的情况是你不改不行
我在看大芒果的wow服务端代码,他用的是ACE网络库,我用IOCP给它发数据,他收到的就是原始的包,包头不记录包大小, 他就是一个字节一个字节在接收,第1个字节就是cmd,表明这个包的用途,根据cmd能知道这个包是什么包,进而确定大小,然后再recv之后的字节。 我最开始封装IOCP就是像你们所说的,包头一律包含4个字节记录包大小,但是我发现人家wow服务端就没有这些约束,所以感觉用4字节保存包大小真是不友好的设计[/quote] 估计你的源代码不对或者你表述得不清楚了 如果按照你说的方法,那怎么区分接收到的数据是否一个包呢? 如果服务器接收的数据被粘包了,你不可能循环所有数据每个字节来对比吧 肯定有一个标志位来区分每个数据包,因为你不知道你收到的数据的第一个字节,是否你发出的数据包,也有可能是被截断了的数据包[/quote] 我一直拿这个wow服务端源码进游戏调试,怎么能说源码不对呢。 我说的已经够详细了,他收到网络包后,先recv第1个字节cmd,根据这个cmd去判断是什么包,然后再recv之后的字节 [/quote] 问题是它怎么保证这个字节就是命令?如果接收到的数据是前一个包的后续数据体呢?[/quote] 那你怎么保证你第1个4字节就是包长度呢?
赵4老师 2015-02-11
  • 打赏
  • 举报
回复
引用 27 楼 Sandrer 的回复:
[quote=引用 24 楼 zhao4zhong1 的回复:] 不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545
看了很多你回答的楼层,你一直都强调base64+\0结束符,问题是如果像你说的数据接收发生错误或者恶意攻击而发送垃圾数据的时候,这个\0终止符一直收不到的话怎么办?[/quote] 问题是如果像你说的数据接收发生错误或者恶意攻击而发送垃圾数据的时候,包长度被篡改的话怎么办?
grf9527 2015-02-11
  • 打赏
  • 举报
回复
自己基于传输协议再定义一个协议。改协议要有严格的自我描述的字段。 通过将接收到的数据连成一串。就可以发现接收到的数据是不是完整的了。 如果是tcp,用户自定义协议可以应对粘包。 如果是udp,只要你的缓冲区够大。收到就是收到,收不到就是收不到了。 基于完成端口的tcp和udp我都做过。基本上就是以上思路解决。
yrisxfyh 2015-02-11
  • 打赏
  • 举报
回复
补充楼上, 贴下wow服务端收到网络包的函数:

void AuthSocket::OnRead()
{
    uint8 _cmd;
    while (1)
    {
        if (!recv_soft((char*)&_cmd, 1))
            return;

        size_t i;

        ///- Circle through known commands and call the correct command handler
        for (i = 0; i < AUTH_TOTAL_COMMANDS; ++i)
        {
            if ((uint8)table[i].cmd == _cmd &&
                    (table[i].status == STATUS_CONNECTED ||
                     (_authed && table[i].status == STATUS_AUTHED)))
            {
                DEBUG_LOG("[Auth] got data for cmd %u recv length %u",
                          (uint32)_cmd, (uint32)recv_len());

                if (!(*this.*table[i].handler)())
                {
                    DEBUG_LOG("Command handler failed for cmd %u recv length %u",
                              (uint32)_cmd, (uint32)recv_len());

                    return;
                }
                break;
            }
        }

        ///- Report unknown commands in the debug log
        if (i == AUTH_TOTAL_COMMANDS)
        {
            DEBUG_LOG("[Auth] got unknown packet %u", (uint32)_cmd);
            return;
        }
    }
}
yrisxfyh 2015-02-11
  • 打赏
  • 举报
回复
引用 25 楼 Sandrer 的回复:
[quote=引用 22 楼 yrisxfyh 的回复:] [quote=引用 21 楼 Sandrer 的回复:] 可以很负责的告诉你,你自己的包不写包头的话,系统是绝不会帮你做的 所有的通讯都是建立在“协议”上的,这个协议并不是 tcp、udp 这些底层网络协议 而是你自己定义的“交流”协议,你所传输的每个应用层数据包,都应该包含有一些简单的数据,例如包大小、包命令等等 不然服务端与客户端之间谁知道在传输什么东西,难道就只是传输1和0? 就算底层的tcp、udp这些网络协议,还不是都一样有包头?包头里面还不照样有包的大小在里面? 我就想不明白为什么一个简单的问题反而被你复杂化了,像你说的服务端不能做任何更改,但目前的情况是你不改不行
我在看大芒果的wow服务端代码,他用的是ACE网络库,我用IOCP给它发数据,他收到的就是原始的包,包头不记录包大小, 他就是一个字节一个字节在接收,第1个字节就是cmd,表明这个包的用途,根据cmd能知道这个包是什么包,进而确定大小,然后再recv之后的字节。 我最开始封装IOCP就是像你们所说的,包头一律包含4个字节记录包大小,但是我发现人家wow服务端就没有这些约束,所以感觉用4字节保存包大小真是不友好的设计[/quote] 估计你的源代码不对或者你表述得不清楚了 如果按照你说的方法,那怎么区分接收到的数据是否一个包呢? 如果服务器接收的数据被粘包了,你不可能循环所有数据每个字节来对比吧 肯定有一个标志位来区分每个数据包,因为你不知道你收到的数据的第一个字节,是否你发出的数据包,也有可能是被截断了的数据包[/quote] 我一直拿这个wow服务端源码进游戏调试,怎么能说源码不对呢。 我说的已经够详细了,他收到网络包后,先recv第1个字节cmd,根据这个cmd去判断是什么包,然后再recv之后的字节
yrisxfyh 2015-02-11
  • 打赏
  • 举报
回复
引用 26 楼 Sandrer 的回复:
[quote=引用 23 楼 yrisxfyh 的回复:] [quote=引用 21 楼 Sandrer 的回复:] 可以很负责的告诉你,你自己的包不写包头的话,系统是绝不会帮你做的 所有的通讯都是建立在“协议”上的,这个协议并不是 tcp、udp 这些底层网络协议 而是你自己定义的“交流”协议,你所传输的每个应用层数据包,都应该包含有一些简单的数据,例如包大小、包命令等等 不然服务端与客户端之间谁知道在传输什么东西,难道就只是传输1和0? 就算底层的tcp、udp这些网络协议,还不是都一样有包头?包头里面还不照样有包的大小在里面? 我就想不明白为什么一个简单的问题反而被你复杂化了,像你说的服务端不能做任何更改,但目前的情况是你不改不行
既然winsocket接口没有告诉我收到的包有多少字节,那我就只能交给应用层去一个字节一个字节的recv了, 总之我想说的是,IOCP的封装类本身不会对网络包有任何约束,外界发什么包,收到的就是什么包。至于协议问题完全交给应用层去设计,IOCP封装库本身是协议无关的。[/quote] 1、系统底层接收到数据包,但这个数据包的包头格式是由系统底层来定义。底层会检查包头数据,看是否收到了正确的数据,如果数据有误,则要求对方重发,如果数据正确,则发送一个确认包给对方,这个重发命令或者确认包命令是不会让你知道的。 2、底层确认数据没问题后,通知中间层有数据到达,这个中间层你可以理解为 GetQueuedCompletionStatus 所监视的内核对象,通知的内容就包含了这些数据的大小(这里的数据大小,你可以理解为底层包的大小或应用层数据的大小,但并不一定是你所需要的应用层包) 3、这时候应用层就可以用 Recv 或 WSARecv 去接收这些数据,大概就是应用层或者底层把接收到的数据复制到你所提供的缓冲区中,然后删除接收到的数据。 4、你自己来分析处理这些数据,看是否能构成你想要的东西。 我自己写的iocp类是把包分析包含在内的(这个所谓的分析也只是把数据组合成一个个应用层数据包),协议是另外一个继承类来处理[/quote] 我是不会把包的分析放在IOCP封装类里,我会把收到的所有字节原封不动的交给应用层去分析, 什么'\0'结束符,什么包头大小,通通没有,这样才具备普遍的适用性。
yrisxfyh 2015-02-10
  • 打赏
  • 举报
回复
引用 21 楼 Sandrer 的回复:
可以很负责的告诉你,你自己的包不写包头的话,系统是绝不会帮你做的 所有的通讯都是建立在“协议”上的,这个协议并不是 tcp、udp 这些底层网络协议 而是你自己定义的“交流”协议,你所传输的每个应用层数据包,都应该包含有一些简单的数据,例如包大小、包命令等等 不然服务端与客户端之间谁知道在传输什么东西,难道就只是传输1和0? 就算底层的tcp、udp这些网络协议,还不是都一样有包头?包头里面还不照样有包的大小在里面? 我就想不明白为什么一个简单的问题反而被你复杂化了,像你说的服务端不能做任何更改,但目前的情况是你不改不行
既然winsocket接口没有告诉我收到的包有多少字节,那我就只能交给应用层去一个字节一个字节的recv了, 总之我想说的是,IOCP的封装类本身不会对网络包有任何约束,外界发什么包,收到的就是什么包。至于协议问题完全交给应用层去设计,IOCP封装库本身是协议无关的。
yrisxfyh 2015-02-10
  • 打赏
  • 举报
回复
引用 21 楼 Sandrer 的回复:
可以很负责的告诉你,你自己的包不写包头的话,系统是绝不会帮你做的 所有的通讯都是建立在“协议”上的,这个协议并不是 tcp、udp 这些底层网络协议 而是你自己定义的“交流”协议,你所传输的每个应用层数据包,都应该包含有一些简单的数据,例如包大小、包命令等等 不然服务端与客户端之间谁知道在传输什么东西,难道就只是传输1和0? 就算底层的tcp、udp这些网络协议,还不是都一样有包头?包头里面还不照样有包的大小在里面? 我就想不明白为什么一个简单的问题反而被你复杂化了,像你说的服务端不能做任何更改,但目前的情况是你不改不行
我在看大芒果的wow服务端代码,他用的是ACE网络库,我用IOCP给它发数据,他收到的就是原始的包,包头不记录包大小, 他就是一个字节一个字节在接收,第1个字节就是cmd,表明这个包的用途,根据cmd能知道这个包是什么包,进而确定大小,然后再recv之后的字节。 我最开始封装IOCP就是像你们所说的,包头一律包含4个字节记录包大小,但是我发现人家wow服务端就没有这些约束,所以感觉用4字节保存包大小真是不友好的设计
Sandrer 2015-02-10
  • 打赏
  • 举报
回复
可以很负责的告诉你,你自己的包不写包头的话,系统是绝不会帮你做的 所有的通讯都是建立在“协议”上的,这个协议并不是 tcp、udp 这些底层网络协议 而是你自己定义的“交流”协议,你所传输的每个应用层数据包,都应该包含有一些简单的数据,例如包大小、包命令等等 不然服务端与客户端之间谁知道在传输什么东西,难道就只是传输1和0? 就算底层的tcp、udp这些网络协议,还不是都一样有包头?包头里面还不照样有包的大小在里面? 我就想不明白为什么一个简单的问题反而被你复杂化了,像你说的服务端不能做任何更改,但目前的情况是你不改不行
Sandrer 2015-02-10
  • 打赏
  • 举报
回复
引用 16 楼 yrisxfyh 的回复:
[quote=引用 15 楼 Sandrer 的回复:] 全世界大部分人都是在包头定义包大小,你要做的是保证按照包顺序来处理就行了 iocp不保证收/发包的顺序的
胡说八道,至少人家ACE收到的包不含包大小[/quote] 系统底层收到数据后,会有一个包头,包头里面就有这个数据包的大小,包是否需要重发的信息都在包头里,系统底层会自动处理(tcp协议)。 但这只是底层的数据包,暂时还不确定是不是你想要的包,当收到数据后会底层通知中间层,但这时底层数据包的包头数据已经被“删”,只保留这个底层数据包的大小 系统中间层处理完后再通知应用层,告诉你端口收到数据和这些数据的大小,你在用recv去把数据从底层“复制”到应用层 数据到了应用层就只是数据,并不是系统底层的包,也不一定是你自己定义的包 后续的操作就要你自己去分析这些数据,看能不能构成你所要的包 你所谓的 “给包头加长度的人都没封装过socket吧” 会被人家笑话你的
飘零风 2015-02-10
  • 打赏
  • 举报
回复
我就想问一句:如果接收到100bytes,你不用“程序”而是用“人脑”来判断,能不能判断出是否接收完成?
Sandrer 2015-02-10
  • 打赏
  • 举报
回复
引用 24 楼 zhao4zhong1 的回复:
不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545
看了很多你回答的楼层,你一直都强调base64+\0结束符,问题是如果像你说的数据接收发生错误或者恶意攻击而发送垃圾数据的时候,这个\0终止符一直收不到的话怎么办?
Sandrer 2015-02-10
  • 打赏
  • 举报
回复
引用 23 楼 yrisxfyh 的回复:
[quote=引用 21 楼 Sandrer 的回复:] 可以很负责的告诉你,你自己的包不写包头的话,系统是绝不会帮你做的 所有的通讯都是建立在“协议”上的,这个协议并不是 tcp、udp 这些底层网络协议 而是你自己定义的“交流”协议,你所传输的每个应用层数据包,都应该包含有一些简单的数据,例如包大小、包命令等等 不然服务端与客户端之间谁知道在传输什么东西,难道就只是传输1和0? 就算底层的tcp、udp这些网络协议,还不是都一样有包头?包头里面还不照样有包的大小在里面? 我就想不明白为什么一个简单的问题反而被你复杂化了,像你说的服务端不能做任何更改,但目前的情况是你不改不行
既然winsocket接口没有告诉我收到的包有多少字节,那我就只能交给应用层去一个字节一个字节的recv了, 总之我想说的是,IOCP的封装类本身不会对网络包有任何约束,外界发什么包,收到的就是什么包。至于协议问题完全交给应用层去设计,IOCP封装库本身是协议无关的。[/quote] 1、系统底层接收到数据包,但这个数据包的包头格式是由系统底层来定义。底层会检查包头数据,看是否收到了正确的数据,如果数据有误,则要求对方重发,如果数据正确,则发送一个确认包给对方,这个重发命令或者确认包命令是不会让你知道的。 2、底层确认数据没问题后,通知中间层有数据到达,这个中间层你可以理解为 GetQueuedCompletionStatus 所监视的内核对象,通知的内容就包含了这些数据的大小(这里的数据大小,你可以理解为底层包的大小或应用层数据的大小,但并不一定是你所需要的应用层包) 3、这时候应用层就可以用 Recv 或 WSARecv 去接收这些数据,大概就是应用层或者底层把接收到的数据复制到你所提供的缓冲区中,然后删除接收到的数据。 4、你自己来分析处理这些数据,看是否能构成你想要的东西。 我自己写的iocp类是把包分析包含在内的(这个所谓的分析也只是把数据组合成一个个应用层数据包),协议是另外一个继承类来处理
Sandrer 2015-02-10
  • 打赏
  • 举报
回复
引用 22 楼 yrisxfyh 的回复:
[quote=引用 21 楼 Sandrer 的回复:] 可以很负责的告诉你,你自己的包不写包头的话,系统是绝不会帮你做的 所有的通讯都是建立在“协议”上的,这个协议并不是 tcp、udp 这些底层网络协议 而是你自己定义的“交流”协议,你所传输的每个应用层数据包,都应该包含有一些简单的数据,例如包大小、包命令等等 不然服务端与客户端之间谁知道在传输什么东西,难道就只是传输1和0? 就算底层的tcp、udp这些网络协议,还不是都一样有包头?包头里面还不照样有包的大小在里面? 我就想不明白为什么一个简单的问题反而被你复杂化了,像你说的服务端不能做任何更改,但目前的情况是你不改不行
我在看大芒果的wow服务端代码,他用的是ACE网络库,我用IOCP给它发数据,他收到的就是原始的包,包头不记录包大小, 他就是一个字节一个字节在接收,第1个字节就是cmd,表明这个包的用途,根据cmd能知道这个包是什么包,进而确定大小,然后再recv之后的字节。 我最开始封装IOCP就是像你们所说的,包头一律包含4个字节记录包大小,但是我发现人家wow服务端就没有这些约束,所以感觉用4字节保存包大小真是不友好的设计[/quote] 估计你的源代码不对或者你表述得不清楚了 如果按照你说的方法,那怎么区分接收到的数据是否一个包呢? 如果服务器接收的数据被粘包了,你不可能循环所有数据每个字节来对比吧 肯定有一个标志位来区分每个数据包,因为你不知道你收到的数据的第一个字节,是否你发出的数据包,也有可能是被截断了的数据包
赵4老师 2015-02-10
  • 打赏
  • 举报
回复
不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545
加载更多回复(18)

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

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