请教,郁闷死了asyncsocket 简书接收大的数据时就接收的不完整

socket 接收数据不全
struct T_TicketingCardInfo_Table
TicketingCardID[20];
TicketTypeID[20];
TCHAR TicketTypeName[20];
TCHAR CardHolderID[20];
TCHAR CardHolderName[20];
TCHAR PersonID[20];
TCHAR StartTime[20];
TCHAR EndTime[20];
TCHAR SendWorkerID[20];
TCHAR SendWorkerName[20];
TCHAR Iseffect[20];
Notes[20];
//发送的信息
struct UserMsg
TCHAR UserName[20];
//管理员名
TCHAR UserPwd[20];
TCHAR IDOfRoom[20];
//终端编号
TCHAR Msg[5000];
//接收到消息
T_TicketingCardInfo_Table
TicketingCardI//售卡信息
上面是我的传输数据结构体
&ErrorMsg = &recv(userInfoList[index].socket, (char *)&TheuserMsg, sizeof(TheuserMsg), 0);
结果发现有时数据全有时不全,后来看了下面的文章才知道一次发送数据有限,我用的是异步通信,所以
TCHAR Msg[5000];
//接收到消息
5000太大了改成20就OK了
在发送端,一次发送4092个字节,
在接收端,一次接收4092个字节,
但是在接收端,偶尔会出现 socket.receive 接收不全的情况 ,
ret = sockTemp.Receive(bBuffer,iBufferLen,0); //也有可能无法收到全部数据!&
必须要考虑0 & ret & iBufferLen的情况:继续接收iBufferLen - ret字节,然后合并
Socket的Send,Recv的长度问题:
一个包没有固定长度,以太网限制在46-1500字节,1500就是以太网的MTU,超过这个量,TCP会为IP数据报设置偏移量进行分片传输,现在一般可允许应用层设置8k(NTFS系统)的缓冲区,8k的数据由底层分片,而应用层看来只是一次发送。
&&&&&&& windows的缓冲区经验值是4k。
&&&&&&& Socket本身分为两种,流(TCP)和数据报(UDP),你的问题针对这两种不同使用而结论不一样。甚至还和你是用阻塞、还是非阻塞Socket来编程有关。
&&&&&&& 1、通信长度,这个是你自己决定的,没有系统强迫你要发多大的包,实际应该根据需求和网络状况来决定。对于TCP,这个长度可以大点,但要知道,Socket内部默认的收发缓冲区大小大概是8K,你可以用SetSockOpt来改变。但对于UDP,就不要太大,一般在1024至10K。注意一点,你无论发多大的包,IP层和链路层都会把你的包进行分片发送,一般局域网就是1500左右,广域网就只有几十字节。分片后的包将经过不同的路由到达接收方,对于UDP而言,要是其中一个分片丢失,那么接收方的IP层将把整个发送包丢弃,这就形成丢包。显然,要是一个UDP发包佷大,它被分片后,链路层丢失分片的几率就佷大,你这个UDP包,就佷容易丢失,但是太小又影响效率。最好可以配置这个值,以根据不同的环境来调整到最佳状态。
&&&&&&& send()函数返回了实际发送的长度,在网络不断的情况下,它绝不会返回(发送失败的)错误,最多就是返回0。对于TCP你可以写一个循环发送。当send函数返回SOCKET_ERROR时,才标志着有错误。但对于UDP,你不要写循环发送,否则将给你的接收带来极大的麻烦。所以UDP需要用SetSockOpt来改变Socket内部Buffer的大小,以能容纳你的发包。明确一点,TCP作为流,发包是不会整包到达的,而是源源不断的到,那接收方就必须组包。而UDP作为消息或数据报,它一定是整包到达接收方。
&&&&&&& 2、关于接收,一般的发包都有包边界,首要的就是你这个包的长度要让接收方知道,于是就有个包头信息,对于TCP,接收方先收这个包头信息,然后再收包数据。一次收齐整个包也可以,可要对结果是否收齐进行验证。这也就完成了组包过程。UDP,那你只能整包接收了。要是你提供的接收Buffer过小,TCP将返回实际接收的长度,余下的还可以收,而UDP不同的是,余下的数据被丢弃并返回WSAEMSGSIZE错误。注意TCP,要是你提供的Buffer佷大,那么可能收到的就是多个发包,你必须分离它们,还有就是当Buffer太小,而一次收不完Socket内部的数据,那么Socket接收事件(OnReceive),可能不会再触发,使用事件方式进行接收时,密切注意这点。这些特性就是体现了流和数据包的区别。
&&&&&&& 补充一点,接收BuffSize &= 发送BuffSize &= 实际发送Size,对于内外部的Buffer都适用,上面讲的主要是Socket内部的Buffer大小关系。
&&&&&&& 3、TCP是有多少就收多少,如果没有当然阻塞Socket的recv就会等,直到有数据,非阻塞Socket不好等,而是返回WSAEWOULDBLOCK。UDP,如果没有数据,阻塞Socket就会等,非阻塞Socket也返回WSAEWOULDBLOCK。如果有数据,它是会等整个发包到齐,并接收到整个发包,才返回。
红色字体是我的,黑色是转载的/staid/archive//1895371.html
> 本站内容系网友提交或本网编辑转载,其目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请及时与本网联系,我们将在第一时间删除内容!
这篇文章主要介绍了C语言中经socket接收数据的相关函数详解,分别为recv函数和recvfrom函数以及recvmsg函数的使用,需要的朋友可以参考下recv()函数:头文件: #include &sys/types.h& #include &sys/socket.h& 定义函数: int recv(int s, void *bu ...
由于Socket 一次传输数据有限,因此需要多次接受数据传输. 解决办法一:
int numberOfBytesRead = 0;
int totalNumberOfBytes = 0;
numberOfBytesRead = mySocket.Receive(receivedData,totalNu ...
以下是由Socket接收到数据,然后再对数据进行解析.
NormalText Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
以前没有注意到有这么一个问题,直到我在用异步socket接收大数据的时候,发现接收数据不是每一次都能一下接收完,可能会分几次才能接收完,这时问题就出现了,怎样判断数据什么时候接收完了呢?我在网上搜了一下,有关这个问题的解答很少,难道大家都没有遇到过这样的问题?还是这个问题本身就不是个问题?不管怎么说,我现在遇到的这种情况是,数据不能保证每一次都能一次 ...
//接收 DWORD RecvBuf(char* cRecvBuf,char* cSocketName,char* cBufName){
int ret=0;
char * cRecvdata=0;
int iRecvdatalen=0;
DWORD begin=0,cur=0;
begin=clock();
在使用loadrunner开发socket脚本的时候,经常遇到lrs_receive这个函数要对接收的数据长度与data.ws这个文件中得预期长度进行对比如果不一致,loadrunner会重复接收,直到超时,所以对于这种情况用户很痛苦.虽然使用:lrs_set_receive_option(EndMarker, StringTerminator ,&quot ...
最近在做项目时,在客户端先将发送的数据进行序列化,然后使用了Tcp进行发送数据,在服务器端进行接收,收到后进行反序列化.当发送的数据量大时,就会出现问题.当时百思不得其解.后来跟踪发送,原来数据并没有一次全部发送过来,而是分了几次发了过来,服务器接收到了多条数据.也就是说,客户端发送一条,服务器端会接收多条.后将程序进行一改良.测试成功.现将心得总结如下:
异步socket Accept数据时使用try catch 捕捉socket 释放异常,服务端监听. try { //同步完成按照msdn解释不会调用Comleted事件 if (!listenSocket.AcceptAsync(listenSocketAsyncEventArgs)) { listenSocketAsyncEventArgs_Comple ...boost::async_read_some连续接收数据
我在最近工作的时候用到了boost的http_server程序,这个http_server是一个框架用于接收并解析http协议。这个框架在接收get请求时没有任何问题,当接收post数据时,当数据大于&2k时,无法正确接收,后来发现sync_read_some函数一次只能接收大约1k数据,如果要接收大数据,需要反复接收,自己修改了几天,将经验分享一下。
//接收数据的buffer
boost::array&char, 8192&
//数据需要多次接收,将多次接收的数据都放入data中
void connection::start()
//超时限制
timer.expires_from_now(boost::posix_time::microseconds(1000000));
timer.async_wait(boost::bind(&connection::close_connect1,this));&
& buffer_.data()[0] = '\0';
& //开始接收数据
&&socket_.async_read_some(boost::asio::buffer(buffer_),
boost::bind(&connection::handle_read1,
shared_from_this(),
& boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred,data));
}void connection::handle_read1(const
boost::system::error_code& e,std::size_t
bytes_transferred,string& data)
//如果超时,返回空
if(!m_flag)
request_handler_.handle_request1(request_, reply_);
&boost::asio::async_write(socket_,
reply_.to_buffers(),
&boost::bind(&connection::handle_write,
shared_from_this(),
&boost::asio::placeholders::error));
& &boost::system::error_code
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both,
ignored_ec);
//如果接收有错误或者接收的数据长度=0,和超时处理一致
if(e || bytes_transferred==0)
request_handler_.handle_request1(request_, reply_);
boost::asio::async_write(socket_, reply_.to_buffers(),
boost::bind(&connection::handle_write,
shared_from_this(),
boost::asio::placeholders::error));
boost::system::error_code ignored_
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both,
ignored_ec);
buffer_.data()[bytes_transferred] = '\0';
data = data + buffer_.data();
//表示接收到了结束标志
if (data.find("|*|*|") != string::npos)
int pos = data.find("|*|*|");
printf("pos=%d\n",pos);
& & data =
data.substr(0,pos);
& if(data.length()&0)
//时钟取消
& timer.cancel();
& //用于处理接收的数据并将处理完的数据返回去,处理完的数据存储在reply中
&request_handler_.handle_request_pos(request_,
reply_,data);
&boost::asio::async_write(socket_,
reply_.to_buffers(),
boost::bind(&connection::handle_write,
shared_from_this(),
boost::asio::placeholders::error));
& request_handler_.handle_request1(request_,
boost::asio::async_write(socket_, reply_.to_buffers(),
boost::bind(&connection::handle_write,
shared_from_this(),
boost::asio::placeholders::error));
& boost::system::error_code ignored_
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both,
ignored_ec);
& //如果上面的if条件不满足,表示还在等待接收数据
socket_.async_read_some(boost::asio::buffer(buffer_),
boost::bind(&connection::handle_read1,
shared_from_this(),
& boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred,
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。用socket可以实现像QQ那样发送即时消息的功能。客户端和服务端需要建立长连接,在长连接的情况下,发送消息。客户端可以发送心跳包来检测长连接。在iOS开发中使用socket,一般都是用第三方库AsyncSocket,不得不承认这个库确实很强大。下载地址/robbiehanson/CocoaAsyncSocket.git。使用AsyncSocket的时候可以做一层封装,根据需求提供几个接口出来。比如:连接、断开连接、发送消息等等。还有接受消息,接受到的消息可以通过通知、代理、block等传出去。简单介绍一下对AsyncSocket使用.一般来说,一个用户只需要建立一个socket长连接,所以可以用单例类方便使用。定义单列类:LGSocketServeLGSocketServe.h//
LGSocketServe.h
AsyncSocketDemo
Created by ligang on 15/4/3.
Copyright (c) 2015年 ligang. All rights reserved.
#import &Foundation/Foundation.h&
#import &AsyncSocket.h&
@interface LGSocketServe : NSObject&AsyncSocketDelegate&
+ (LGSocketServe *)sharedSocketS
@endLGSocketServe.m//
LGSocketServe.m
AsyncSocketDemo
Created by ligang on 15/4/3.
Copyright (c) 2015年 ligang. All rights reserved.
#import &LGSocketServe.h&
@implementation LGSocketServe
static LGSocketServe *socketServe =
#pragma mark public static methods
+ (LGSocketServe *)sharedSocketServe {
@synchronized(self) {
if(socketServe == nil) {
socketServe = [[[self class] alloc] init];
return socketS
+(id)allocWithZone:(NSZone *)zone
@synchronized(self)
if (socketServe == nil)
socketServe = [super allocWithZone:zone];
return socketS
@end建立socket长连接LGSocketServe.h@property (nonatomic, strong) AsyncSocket
socket连接
- (void)startConnectSLGSocketServe.m//自己设定
#define HOST @&192.168.0.1&
#define PORT 8080
//设置连接超时
#define TIME_OUT 20
- (void)startConnectSocket
self.socket = [[AsyncSocket alloc] initWithDelegate:self];
[self.socket setRunLoopModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
if ( ![self SocketOpen:HOST port:PORT] )
- (NSInteger)SocketOpen:(NSString*)addr port:(NSInteger)port
if (![self.socket isConnected])
NSError *error =
[self.socket connectToHost:addr onPort:port withTimeout:TIME_OUT error:&error];
}宏定义一下HOST、PORT、TIME_OUT,实现startConnectSocket方法。这个时候要设置一下AsyncSocket的代理AsyncSocketDelegate。当长连接成功之后会调用:- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
//这是异步返回的连接成功,
NSLog(@&didConnectToHost&);
}心跳LGSocketServe.h@property (nonatomic, retain) NSTimer
// 心跳计时器LGSocketServe.m- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
//这是异步返回的连接成功,
NSLog(@&didConnectToHost&);
//通过定时器不断发送消息,来检测长连接
self.heartTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(checkLongConnectByServe) userInfo:nil repeats:YES];
[self.heartTimer fire];
// 心跳连接
-(void)checkLongConnectByServe{
// 向服务器发送固定可是的消息,来检测长连接
NSString *longConnect = @&connect is here&;
= [longConnect dataUsingEncoding:NSUTF8StringEncoding];
[self.socket writeData:data withTimeout:1 tag:1];
}在连接成功的回调方法里,启动定时器,每隔2秒向服务器发送固定的消息来检测长连接。(这个根据服务器的需要就可以了)断开连接1,用户手动断开连接LGSocketServe.h// 断开socket连接
-(void)cutOffSLGSocketServe.m-(void)cutOffSocket
self.socket.userData = SocketOfflineByU
[self.socket disconnect];
}cutOffSocket是用户断开连接之后,不在尝试重新连接。2,wifi断开,socket断开连接LGSocketServe.m- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
NSLog(@& willDisconnectWithError %ld
err = %@&,sock.userData,[err description]);
if (err.code == 57) {
self.socket.userData = SocketOfflineByWifiC
}wifi断开之后,会回调onSocket:willDisconnectWithError:方法,err.code == 57,这个时候设置self.socket.userData = SocketOfflineByWifiCut。重新连接socket断开之后会回调:LGSocketServe.m- (void)onSocketDidDisconnect:(AsyncSocket *)sock
NSLog(@&7878 sorry the connect is failure %ld&,sock.userData);
if (sock.userData == SocketOfflineByServer) {
// 服务器掉线,重连
[self startConnectSocket];
else if (sock.userData == SocketOfflineByUser) {
// 如果由用户断开,不进行重连
}else if (sock.userData == SocketOfflineByWifiCut) {
// wifi断开,不进行重连
}在onSocketDidDisconnect回调方法里面,会根据self.socket.userData来判断是否需要重新连接。发送消息LGSocketServe.h// 发送消息
- (void)sendMessage:(id)LGSocketServe.m//设置写入超时 -1 表示不会使用超时
#define WRITE_TIME_OUT -1
- (void)sendMessage:(id)message
//像服务器发送数据
NSData *cmdData = [message dataUsingEncoding:NSUTF8StringEncoding];
[self.socket writeData:cmdData withTimeout:WRITE_TIME_OUT tag:1];
//发送消息成功之后回调
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
}发送消息成功之后会调用onSocket:didWriteDataWithTag:,在这个方法里可以进行读取消息。接受消息LGSocketServe.m//设置读取超时 -1 表示不会使用超时
#define READ_TIME_OUT -1
#define MAX_BUFFER 1024
//发送消息成功之后回调
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
//读取消息
[self.socket readDataWithTimeout:-1 buffer:nil bufferOffset:0 maxLength:MAX_BUFFER tag:0];
//接受消息成功之后回调
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
//服务端返回消息数据量比较大时,可能分多次返回。所以在读取消息的时候,设置MAX_BUFFER表示每次最多读取多少,当data.length & MAX_BUFFER我们认为有可能是接受完一个完整的消息,然后才解析
if( data.length & MAX_BUFFER )
//收到结果解析...
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
NSLog(@&%@&,dic);
//解析出来的消息,可以通过通知、代理、block等传出去
[self.socket readDataWithTimeout:READ_TIME_OUT buffer:nil bufferOffset:0 maxLength:MAX_BUFFER tag:0];接受消息后去解析,然后可以通过通知、代理、block等传出去。在onSocket:didReadData:withTag:回调方法里面需要
不断读取消息,因为数据量比较大的话,服务器会分多次返回。所以我们需要定义一个MAX_BUFFER的宏,表示每次最多读取多少。当
data.length & MAX_BUFFER我们认为有可能是接受完一个完整的消息,然后才解析
。出错处理LGSocketServe.m- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
NSData * unreadData = [sock unreadData]; // ** This gets the current buffer
if(unreadData.length & 0) {
[self onSocket:sock didReadData:unreadData withTag:0]; // ** Return as much data that could be collected
NSLog(@& willDisconnectWithError %ld
err = %@&,sock.userData,[err description]);
if (err.code == 57) {
self.socket.userData = SocketOfflineByWifiC
}socket出错会回调onSocket:willDisconnectWithError:方法,可以通过unreadData来读取未来得及读取的buffer。使用导入#import “LGSocketServe.h” LGSocketServe *socketServe = [LGSocketServe sharedSocketServe];
//socket连接前先断开连接以免之前socket连接没有断开导致闪退
[socketServe cutOffSocket];
socketServe.socket.userData = SocketOfflineByS
[socketServe startConnectSocket];
//发送消息 @&hello world&只是举个列子,具体根据服务端的消息格式
[socketServe sendMessage:@&hello world&];以上是AsyncSocket的简单使用,在实际开发过程中依然会碰到很多问题,欢迎加我的微信公众号iOS开发:iOSDevTip,一起讨论AsyncSocket中遇到的问题。●本文编号97,以后想阅读这篇文章直接输入97即可。●本文分类“AsyncSocket、socket”,直接回复分类名可以获得相关文章。●输入m可以获取到全部文章目录如果你觉得iOS开发公众微信对你有帮助,请点击右上角“...”标志分享到【朋友圈】,感谢支持!合作请联系微信:chinaligang
iOS开发(iOSDevTip) 
 文章为作者独立观点,不代表大不六文章网立场
iOSDevTip最新iOS、iPhone资讯,万名iOS开发者、swift开发、果粉聚集,参与技术讨论,整理开发技巧,分享创业经验!享受生活、热爱编程!热门文章最新文章iOSDevTip最新iOS、iPhone资讯,万名iOS开发者、swift开发、果粉聚集,参与技术讨论,整理开发技巧,分享创业经验!享受生活、热爱编程!&&&&违法和不良信息举报电话:183-
举报邮箱:
Copyright(C)2016 大不六文章网
京公网安备78}

我要回帖

更多关于 ios cocoaasyncsocket 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信