收录日期:2018/11/19 05:27:29 时间:2016/07/26 20:16:53 标签:应用程序开发区
在AIX机器上接收客户端的报文,将其中的图像处理之后返回给客户端。数据量特大。

怎么保证顺利接收和发送。
如果采用非阻塞方式,则返回给客户端的数据量太太,远超过发送buffer大小(设太太大肯定不行),分开发送,接收端接收到的数据不对,如果采用阻塞方式的话,如果客户端告知的数据长度比实际发送来的长度大,则导致一直等待客户端发送数据。


有什么好的解决办法吗?

谢谢。




现在用的是非阻塞方式。
int value = 1;
ioctl(sockfd, FIONBIO, (char *)&value, sizeof(value));
然后又设置了发送buffer和接收buffer的大小。

可是我现在需要的是发送大块的图像数据,可能达10M。
发送的时候,如果分多次发送,则接收端会多收到一些数据,而且是在两次发送中间。
发送代码如下:
long len = image_len;
long rest = len;
while(rest > 0)
{
  count = send(sockfd, ptr, SEND_BUFFER_SIZE < rest ? SEND_BUFFER_SIZE : rest, 0);
  ptr += count;
  rst -= count;
}

发送完之后,在服务端没发现异常,在客户端(windows上)接收到的数据,则比发送的要多,而且图像跟服务端发送的图像不一像了,多了一些黑块。而且每次接收到的大小会变化。


该怎么办呢?

之所以采用非阻塞方式,因为如果采用阻塞方式的话,接收会有问题:
接收格式为:长度,数据。
如果客户端发送的报文中长度比实际发送的数据要大的话,导致阻塞。
long len = image_len;
long rest = len;
while(rest > 0)
{
  count = read();
  rest -= count;
}
如果len = 10000, 实际发过来的数据长度为8000,则会阻塞在count = read()语句上。


请大虾赐教。如果采用阻塞方式,则需解决接收的问题,如果采用非阻塞方式,则需解决发送的问题。

另外,不可能采用分包方式。不是技术原因。
如果设置成阻塞模式,设置接收的超时选项,或者用alarm设置定时器,如何?
用alarm怎样单纯地从recv()函数中跳出?
struct timeval timeout;
/* 30 Secs Timeout */
timeout.tv_sec = 30;
timeout.tv_usec = 0;

setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,(struct timeval *)&timeout, sizeof(struct timeval));
设置SO_RCVTIMEO,
如果有数据read/recv会返回已经读到的数据的字节数,
如果没有数据会返回-1并设置errno为EAGAIN或者EWOULDBLOCK
引用楼主 liaozhicai 的回复:
如果客户端发送的报文中长度比实际发送的数据要大的话,导致阻塞。

客户端发送的长度??不是服务器发送报文吗?
引用 4 楼 justkk 的回复:
引用楼主 liaozhicai 的回复:如果客户端发送的报文中长度比实际发送的数据要大的话,导致阻塞。
客户端发送的长度??不是服务器发送报文吗?


客户端发送报文给服务器,格式是[二进制数据长度][二进制数据]
服务器将二进制数据处理后按约定的格式返回给客户端。

如果客户端发送的报文有误,如[10][111100001],
报文中长度字段解析出来为10,但其后的数据实际只有9,使用
while(rest>0)
{
  count = read();
  rest -= count;
}
接收数据。count =9, rest = 1;之后进入while(rest>0)循环,阻塞在count = read()语句上。
(实际中可能数据长度可能是几百万之多,故不可能一次性接收,只好通过while循环)。



目前我是用alarm解决了问题,通过设置SO_RCVTIMEO参数不管用,因为实际系统为AIX5.3,一查man setsockopt,结果告知:SO_RCVTIMEO is setable, but unuseable.


通过alarm直接退出进程。但希望能通过alarm直接跳出read()语句。
你这根本原因还是客户端发送的长度有误啊,明明只有8个字节,非说发送了10个字节..

抛开客户端不管,服务端想退出read()也是可以的..
比较适合的方法是使用select()

使用alarm()也可以,调用简单一些,你需要设置信号处理动作
在你的程序中添加信号处理函数的定义,空的函数体就行 void foo(int sig) {}
然后signal(SIGALRM, foo);
引用 6 楼 justkk 的回复:
你这根本原因还是客户端发送的长度有误啊,明明只有8个字节,非说发送了10个字节..

抛开客户端不管,服务端想退出read()也是可以的..
比较适合的方法是使用select()

使用alarm()也可以,调用简单一些,你需要设置信号处理动作
在你的程序中添加信号处理函数的定义,空的函数体就行 void foo(int sig) {}
然后signal(SIGALRM, foo);……



我现在用的就是select,用的是阻塞式的select,如果用非阻塞式的select,是没问题的,但用非阻塞式的select的话,用while(rest > 0)循环发送大容量数据,结果在客户端接收到的数据比发送的还多,而且每次收到的数量还不一定相同,所以才用阻塞式的select,而且用非阻塞式的select,由于EWOULDBLOCK次数太多,结果比用阻塞式的select要慢不少。
引用 6 楼 justkk 的回复:
你这根本原因还是客户端发送的长度有误啊,明明只有8个字节,非说发送了10个字节..

抛开客户端不管,服务端想退出read()也是可以的..
比较适合的方法是使用select()

使用alarm()也可以,调用简单一些,你需要设置信号处理动作
在你的程序中添加信号处理函数的定义,空的函数体就行 void foo(int sig) {}
然后signal(SIGALRM, foo);……



空的alarm响应函数不行的吧,我试了一下,不退出进程,打印后直接return,结果进程还是阻塞的
引用 7 楼 liaozhicai 的回复:
结果在客户端接收到的数据比发送的还多,而且每次收到的数量还不一定相同

这是你程序逻辑问题了,这怎么可能??
引用 7 楼 liaozhicai 的回复:
所以才用阻塞式的select,而且用非阻塞式的select,由于EWOULDBLOCK次数太多,结果比用阻塞式的select要慢不少

阻塞式的select?? 非阻塞式的select??
只听说过socket本身的阻塞与否
使用select的目的就是为了避免socket操作的阻塞,select用来判断socket描述符是否可读/可写,select返回之后,程序可以操作描述符,这时候怎么还会EWOULDBLOCK呢??
引用 8 楼 liaozhicai 的回复:
空的alarm响应函数不行的吧,我试了一下,不退出进程,打印后直接return,结果进程还是阻塞的

信号的目的是中断read操作,此时read会返回一个错误,怎么处理这个错误取决于你的程序自己了。。
引用 10 楼 justkk 的回复:
引用 8 楼 liaozhicai 的回复:空的alarm响应函数不行的吧,我试了一下,不退出进程,打印后直接return,结果进程还是阻塞的
信号的目的是中断read操作,此时read会返回一个错误,怎么处理这个错误取决于你的程序自己了。。



非常谢谢。

我再仔细设计一下程序结构。



请教一个查询语句 只编译exe文件,是否可行? 一个button控制多个button的问题 我要做一个产品列表是根据产品卖出的数量来排列的。下面是代码,可是效果出不来。麻烦高手们帮我看看 数据库设计--流程处理 怎么在mschart中画水平线 辞职了,换了新工作..........散分了.... 如何给程序加密? 请问高手们一个extjs editgrid 和 combobox的问题,老问题的.但是我从网上找的资料解决不了我的为难题 用了10分钟做了个小玩意:字符画转换 在VB.NET中改变显示器的分辩率 非常非常简单的问题sql语句问题 VC6下 生成一个DLL里要调用其他LIB实现的函数,怎么引用?? delphi7 编译原理词法分析器 正规式到NFA的转化,NFA到DFA、DFA到MFA 我又来请教正则表达式了 installshield12怎么样编写脚本 求一个linq查询,高手请指点了。。。 求sql如何把这些结果合并成一条记录 水晶报表一页内同列多个相同的详细资料部的问题 有用dojo的XDJM没? 给四分妹散分 从来就没有什么救世主,也不靠神仙皇帝,要创造人类的幸福,全靠我们自己!我们要夺回劳动果实,让思想冲破牢笼。快把那炉火烧的通红,趁热打铁才能成功! 请有经验的朋友推荐一本测试书藉 winform crystal report设置每页显示记录数目不起效 javascript 中form 提交方式区别的问题 拒接来电后,全屏窗口下方出现了输入法按钮,如何消掉它? 求助 ---- 关于生育二胎的问题 是谁创造了人类世界?是我们劳动群众。一切归劳动者所有,哪能容得寄生虫!最可恨那些毒蛇猛兽,吃尽了我们的血肉。一旦把他们消灭干净,鲜红的太阳照遍全球! 寻人合作开发建筑类相关软件 关于gsoap,遇到“error LNK2019: 无法解析的外部符号”问题,请求大虾的帮助!!!