第一次接通讯服务器的任务,设计上有点问题,有经验的前辈给个建议

The_facE 2009-12-22 09:16:04
通讯服务器,客户端发送申请,服务器处理数据然后回复。服务器端程序需要重构。
Select模型,但不是select->accept->recv方式,而是accept->select->recv(这个是不能更改的,我们头儿这么要求的)。

有的报文会有一个很长而并不需要处理的头信息,有的没有,而且整个报文数据部分的长度保存在报文的前几十个字节中(不算那个很长的无用报文头),现在我不决的是:
1.将一个报文分多次recv,比如:先recv一小段信息,处理有无用报文头的情况,然后再recv一段,判断报文数据长度,最后再一次recv完成。
2.一次recv一个可能的最大长度,然后再处理报文。

哪种方式会比较好?

另:经常发生select通过而recv到0的情况,不知道为什么?基本可以确定不是客户端断开连接,因为旧的服务器程序从不发生这种现象。
...全文
136 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
The_facE 2009-12-23
  • 打赏
  • 举报
回复
嗯嗯,大家说的我都学习了。非常感谢。最终问题还是我自己写的代码不仔细。

因为服务器程序是重构,因此我使用了很多原来的代码,所以很主观的认为既然用了select就会把socket设置成非阻塞的,结果在循环接收时造成recv阻塞,长时间没有回复,而客户端超时无回复时自动断开了连接,造成recv返回0,再转回select的时候就无法阻塞了。教训啊。

结贴了,再次感谢各位。
fangjm2009 2009-12-22
  • 打赏
  • 举报
回复
学习下
The_facE 2009-12-22
  • 打赏
  • 举报
回复
新的问题哈,终于发现了,不是recv 0的问题,而是select没有阻塞直接返回1了,这是为什么呢?
select段代码如下:

fd_set fdRead;
FD_ZERO( &fdRead );
FD_SET( GetSocket(), &fdRead );
if ( select( 0, &fdRead, NULL, NULL, NULL ) <= 0 )
{
TRACE( "Thread %d : Select failed!", GetCurrentThreadId() ); return 0;
}
if (FD_ISSET( GetSocket(), &fdRead))
{
/*....*/
}
The_facE 2009-12-22
  • 打赏
  • 举报
回复
谢谢各位,我先改一下recv部分的代码,然后再说哈。
  • 打赏
  • 举报
回复
针对客户端的一次发送请求,在通讯服务器来说还是一次接收,然后再处理的比较好一些。
既然是通讯,各个不同的报文如何处理一定会不一样的,这样的话,在接收到报文处理起来更容易把握一些,更不易出错。

第二个问题,你确认一下你Select的套接字的状态是否只检测了套接字的可读性,如果有其他的状态的话,而不是可读的话,select也会返回的了。

仅供参考。
andywei1982 2009-12-22
  • 打赏
  • 举报
回复
用iocp来处理连上来的客户端和选择客户端发送数据,
sandyandy 2009-12-22
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 wenxy1 的回复:]
通讯服务器,客户端发送申请,服务器处理数据然后回复。服务器端程序需要重构。
Select模型,但不是select->accept->recv方式,而是accept->select->recv(这个是不能更改的,我们头儿这么要求的)。
Answer: 你们头儿很无知,没有理解select模型。

有的报文会有一个很长而并不需要处理的头信息,有的没有,而且整个报文数据部分的长度保存在报文的前几十个字节中(不算那个很长的无用报文头),现在我不决的是:
1.将一个报文分多次recv,比如:先recv一小段信息,处理有无用报文头的情况,然后再recv一段,判断报文数据长度,最后再一次recv完成。
2.一次recv一个可能的最大长度,然后再处理报文。

哪种方式会比较好?
Answer: 无用报文和有用报文,应当通过一个头部标识来识别。recv()一个可能的最大长度会更高效,软中断也是比较费时间的。

另:经常发生select通过而recv到0的情况,不知道为什么?基本可以确定不是客户端断开连接,因为旧的服务器程序从不发生这种现象。
Answer:  If the connection has been gracefully closed, the return value is zero.这是MSDN的解释,是客户端断开。
[/Quote]

很详细
Wenxy1 2009-12-22
  • 打赏
  • 举报
回复
通讯服务器,客户端发送申请,服务器处理数据然后回复。服务器端程序需要重构。
Select模型,但不是select->accept->recv方式,而是accept->select->recv(这个是不能更改的,我们头儿这么要求的)。
Answer: 你们头儿很无知,没有理解select模型。

有的报文会有一个很长而并不需要处理的头信息,有的没有,而且整个报文数据部分的长度保存在报文的前几十个字节中(不算那个很长的无用报文头),现在我不决的是:
1.将一个报文分多次recv,比如:先recv一小段信息,处理有无用报文头的情况,然后再recv一段,判断报文数据长度,最后再一次recv完成。
2.一次recv一个可能的最大长度,然后再处理报文。

哪种方式会比较好?
Answer: 无用报文和有用报文,应当通过一个头部标识来识别。recv()一个可能的最大长度会更高效,软中断也是比较费时间的。

另:经常发生select通过而recv到0的情况,不知道为什么?基本可以确定不是客户端断开连接,因为旧的服务器程序从不发生这种现象。
Answer: If the connection has been gracefully closed, the return value is zero.这是MSDN的解释,是客户端断开。
cnzdgs 2009-12-22
  • 打赏
  • 举报
回复
一次recv一个可能的最大长度,但要根据recv的返回值确定收到了多少数据,如果数据没有收全,还要继续接收。
select返回1说明已经有数据进来了,接着执行recv返回0吗?把代码贴上。

18,356

社区成员

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

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