socket网络编程中返回值的含义
正文
最近学习socket网络编程,总结一下其中recv和send的返回值以及对应的含义
recv()方法
模型:
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
参数:
- sockfd:创建的文件描述符fd
- buf:接收数据的缓冲区
- len:接收数据的长度
- flags:表示信息,默认设置为0
当应用程序调用recv接收数据的时候,recv函数会等待sockfd中发送数据的缓冲区的协议发送完数据,如果在等待过程中出现网络错误,则会返回SOCKET_ERROR。如果sockfd中的缓冲区中没有数据或者协议已经发送完数据,则recv会检查sockfd的接收缓冲区,如果该缓冲区正在接收数据,则recv会一直等待,直到缓冲区接收数据完毕,之后recv将数据从缓冲区拷贝一份至buf中。注意,数据是通过协议转发的,recv()只是将数据从缓冲区拷贝过来。如果recv()在拷贝数据时出现错误,则返回SOCKET_ERROR,如果在协议传输数据中出现网络错误,则返回0.
阻塞与非阻塞模式下recv()的**返回值没有区别!!!**都是:
- <0:出错
- =0:对方调用了close()来关闭连接
- >0:接收到的数据大小
**注意:返回值<0时是有很多含义的,具体还要看此时的errno的值。比如返回值<0,并且errno==EINTR||errno==EWOULDBLOCK||errno==EAGAIN,此时人情连接时正常的,继续接收**
但是在阻塞模式下就不会出现这种情况,因为这种情况默认也是阻塞。
具体的返回值类型:
-
>0:成功执行时,返回接收到的字节数
-
=0:若另一端已关闭连接则返回0,这种关闭是对方主动且正常的关闭
-
<0:失败,返回-1,且errno被设置为以下的某个值
- EAGAIN:套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
- EBADF:sockfd不是有效的描述符
- ECONNREFUSE:远程主机拒绝网络连接
- EFAULT:内存空间访问出错
- EINTR:操作被信号中断
- EINVAL:参数无效
- ENOMEM:内存不足
- ENOTCONN:与面向连接关联的套接字尚未被连接上
- ENOTSOCK:sockfd不是套接字
send()方法
模型:
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
参数:
- sockfd:创建的sockfd文件描述符
- buf:发送数据所在的数据区
- len:发送数据的长度
- flags:标志位,默认设置为0
当程序使用send()方法时,send()会首先检查协议sockfd中的发送缓冲区中是否有数据发送,send()会比较发送数据的buf长度和sockfd发送数据的缓冲区长度,如果len大于sockfd的发送长度,则send()返回SOCKET_ERROR,如果发送缓冲区的大小足够,则将数据buf中的数据发送至发送缓冲区中,确认send()函数将数据拷贝至发送缓冲区中。另外,如果send()检测发送缓冲区有数据但是还未发送,就比较该缓冲区的剩余空间和len的大小,如果len大于剩余空间,就一直等待,直到缓冲区中的数据发送完为止,如果len小于缓冲区的剩余大小,那么九江待发送的数据拷贝至缓冲区中,如果send函数copy数据成功,就返回实际copy的字节数,如果send()函数在拷贝数据时出现错误,那么send()就返回SOCKET_ERROR;如果send()在等待协议传送数据时网络断开的话,那么send()函数也返回SOCKET_ERROR。
(需要注意的是,默认情况下send()函数只是将数据拷贝至发送缓冲区中,就返回了,此刻数据不一定立刻就发送至接收端,若想数据在发送缓冲区中不做合包立刻发送,需要利用setsockopt()函数对套接字进行设置)
返回值作用与上文recv()方法相同。
总结
无论是send()还是recv()方法,都是对数据的接收缓冲区和发送缓冲区进行拷贝的过程,真正发送数据的是协议功能。