
不管怎么说,在recv之前调用一下select(),检查缓冲到底有没有内容,如果有,再执行recv就不会有任何问题。而且 select的好处是,如果没有接到别的东西,你可以sleep()一下,不占用CPU
用下面的rcv代替你的recv函数吧,我在嵌入式系统开发时自己写的一个标准例程,很可靠:
参数解释:
sck - socket
buf - 接收缓冲区
size-缓冲区大小
time_out-等待时间(按秒计)如果超时则返回
返回值:收到字节数,0表示超时等错误
int rcv(int sck, void * buf, int size, int time_out)
{
if (sck <1 || !buf || size <1) return 0
timeval tv = { 0, 0}timeval * ptv = 0
if (time_out >0) { tv.tv_sec = time_outptv = &tv}
memset(buf, 0, size)
int r = 0char * b = (char*) bufint sz = size
fd_set rd, erint total = 0time_t t0 = time(0)time_t t1 = 0
do {
FD_ZERO(&rd)FD_SET(sck, &rd)
FD_ZERO(&er)FD_SET(sck, &er)
r = select(sck + 1, &rd, 0, &er, ptv)
if (r == -1) { nperror("select()")return -1}
if (FD_ISSET(sck, &er)) {
nperror("socket(shutdown)")return -1
}//end if
if (FD_ISSET(sck, &rd)) {
r = recv(sck, b, sz, 0)
if (r == -1) { nperror("recv()")return -1}
total += rsz -= rb+= r
}//end if
if (time_out >0)
t1 = time(0) - t0
else
t1 = time_out - 1
//end if
}while(sz &&t1 <time_out)
return total
}//end if
1、recv是socket编程中最常用的函数之一,在阻塞状态的recv有时候会返回不同的值,而对于错误值也有相应的错误码,分别对应不同的状态。2、recv函数只是在用户空间定义的。内核空间有与之对应的函数,也就是说,执行recv函数就会调用到内核中与它对应的函数,实际起作用的就是内核里的这个函数。至于内核里调用的是那个函数,内核里的调用关系复杂的很,除非对内核非常了解的,才会找到到底是怎么调用的,他也是只是找到怎么调用的。
int socketdomain指明所使用的协议族,通常为PF_INET,表示互联网协议族;type参数指定socket的类型:SOCK_STREAM 或SOCK_DGRAM,Socket接口还定义了原始Socket,允许程序使用低层协议;protocol通常赋值"0"。
Socket()调用返回一个整型socket描述符,你可以在后面的调用使用它。 Socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。
调用Socket函数时,socket执行体将建立一个Socket,实际上"建立一个Socket"意味着为一个Socket数据结构分配存储空间。 Socket执行体为你管理描述符表。
扩展资料:
支持下述类型描述:
SOCK_STREAM 提供有序的、可靠的、双向的和基于连接的字节流,使用带外数据传送机制,为Internet地址族使用TCP。
SOCK_DGRAM 支持无连接的、不可靠的和使用固定大小(通常很小)缓冲区的数据报服务,为Internet地址族使用UDP。
SOCK_STREAM类型的套接口为全双向的字节流。对于流类套接口,在接收或发送数据前必需处于已连接状态。用connect()调用建立与另一套接口的连接,连接成功后,即可用send()和recv()传送数据。当会话结束后,调用close()。带外数据根据规定用send()和recv()来接收。
参考资料来源:百度百科-socket函数
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)