收录日期:2019/04/24 08:30:07 时间: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会返回一个错误,怎么处理这个错误取决于你的程序自己了。。



非常谢谢。

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



关于软驱写保护的问题 在asp中,怎样用javascpipt传很多的值 指点指点我如何解决Kylix2编译CORBAidl时的java路径问题吧!!:) 怎么用VB做 RM 播放程序? 是中国频道的空间不能用cookie对象吗?出现如下错误提示!!! 突然觉得很兴奋,半夜起来发贴 硬盘序列号 有关clientsocket的奇怪问题 有关clientsocket的奇怪问题 为什么Web页面不能调用ActiveX中的方法? 求助,一定加分 设定了CTreeView的外观为TVS_HASLINES,然而还是看不到线? 关于多线程,执行先后的问题。望给与提示。谢谢! 在C++builder里如何c++builder实现网页的超连接效果 怎样给一个对话框程序添加一个工具条??? 怎样实现在位图背景上花圆(最好有源代码) 谁有屏幕抓词的原码?货到给份。。。。。 深圳的朋友帮帮忙,关于系统分析员考试报名时间、地点或联系电话。谢谢! 装了阳春白雪之后,KDE的字体确实美多了,但GNOME的字体还是这么丑,为什么呢? BCB安装组件的问题,请求帮助,多谢! 远程监控中怎样获取对方屏幕? Linux有没有一个能够像windows下的智能ABC般,可以自己创建词组,而又提供模糊音的输入法软件呢? delphi里面二进制、十六进制的表示及指针问题 夜猫子签到!祝你节日快乐! 牛仔的程序员爱情长篇小说--《等待的QQ》第二章! 请教各位,为什莫我在安装完C++Builder 之后的帮助向里面只有“目录”和“索引”,另外的那一项怎莫没有啊? 图标。如何添加图标? 各位五一快乐 太爽了,曼联被淘汰出局了!特来此庆贺 如何在程序运行期间用代码在access 2000的库文件中的表中加入新的字段