Linux网络编程:recv的返回值
recv是网络编程中用于TCP传输接收数据的接口,由于工作中一直没有接触到网络编程,虽然知道这个函数,但是没有使用经验,所有对接口细节不是很了解。
直到前阵子在项目中调试第三方的源码时,跟踪到这个函数,才发现它的返回值和我想象的不太一样。
recv函数的原型:
ssize_t recv(int sockfd, void* buf, size_t len, int flags);
之前知道的是如果读取成功,会返回实际读取到的字节数,但是如果读取不到数据呢?一直想当然的认为会返回0,其实并不是,当读取不到数据的时候,返回的是-1,错误码是11,对应的含义是:Resource temporarily unavailable,这里的资源自然是指要读取的数据,因为没有数据可以读取,所以资源不可用。
那么返回值为0表示什么意思?答案是当对端关闭了socket的时候(是真正地关闭,会引发四次握手,而不是减少引用),我们再去调用recv读取数据,会返回0。
下面是测试代码,连接建立后,服务端会网socket发送数据,每次发送后sleep5秒,当发送四次数据后,关闭socket。为了测试在没有数据可读的情况下调用recv的返回值,我们在客户端把socket设置为非阻塞模式,当服务端在sleep时,socket没有数据可读,调用recv后会返回-1,打印出来的错误码是11,当服务端关闭了socket后,再次调用recv则返回0。
服务端代码:
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <netdb.h>using namespace std;#define MAX_OF_LISTEN_QUEUE 10
#define MAXBUF 1024int main(){int sockFd;int destSockFd;struct sockaddr_in source;struct sockaddr_in dest;char buff[MAXBUF+1];memset(&source, 0, sizeof(source));source.sin_family = AF_INET;source.sin_port = htons(8235);source.sin_addr.s_addr = inet_addr("192.168.1.109");sockFd = socket(AF_INET, SOCK_STREAM, 0);if(sockFd < 0){cout << "created server socket error!" << endl; }if(bind(sockFd, (struct sockaddr*)&source, sizeof(source)) != 0){cout << "server bind error!" << endl; }if(listen(sockFd, MAX_OF_LISTEN_QUEUE) != 0){cout << "server listen error!" << endl;}socklen_t len = sizeof(dest); while(1){destSockFd = accept(sockFd, (struct sockaddr*)&dest, &len);if(destSockFd == -1){cout << "server accept error!" << endl;}else{cout << "server accept a connection!" << endl;break; }}int hasSend;strcpy(buff, "This message from server!");int count = 0;while(1){count++;if(count > 4)break;sleep(5);cout << "server sending message!" << endl;hasSend = send(destSockFd, buff, strlen(buff), 0); if(hasSend == -1){cout << "server send message error!" << endl; }if(hasSend == strlen(buff)){cout << "server send OK!" << endl; }else{cout << "server only send " << hasSend << "bytes!" << endl; }} close(destSockFd); cout << "server will exit!" << endl;
}
客户端代码:
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <netdb.h>
#include <sys/select.h>
#include <fcntl.h>using namespace std;#define MAXSLEEP 128
#define MAXBUF 1024int main(){int sockFd;struct sockaddr_in dest;struct sockaddr_in source;char buff[MAXBUF+1];sockFd = socket(AF_INET, SOCK_STREAM, 0);if(sockFd < 0){cout << "created client socket error!" << endl; }memset(&dest, 0, sizeof(dest));dest.sin_family = AF_INET;dest.sin_port = htons(8235);dest.sin_addr.s_addr = inet_addr("192.168.1.109");memset(&source, 0, sizeof(source));source.sin_family = AF_INET;source.sin_port = htons(8234);source.sin_addr.s_addr = inet_addr("192.168.1.109");if(bind(sockFd, (struct sockaddr*)&source, sizeof(source)) != 0){cout << "client bind error!" << endl; }//use exponential backoffint nsec;for(nsec = 1; nsec <= MAXSLEEP; nsec <<= 1){if(connect(sockFd, (struct sockaddr*)&dest, sizeof(dest)) == 0){cout << "connect to server successfully, will break" << endl;break; }if(nsec <= MAXSLEEP/2){cout << "connect to server error, will sleep " << nsec << "seconds!" << endl;sleep(nsec); }}int flag = fcntl(sockFd, F_GETFL, 0);flag |= O_NONBLOCK;fcntl(sockFd, F_SETFL, flag);int recvLen;//setsockopt(sockFd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));while(1){cout << "client recving message!" << endl;recvLen = recv(sockFd, buff, MAXBUF, 0);if(recvLen == -1){cout << "client recv message error!" << endl;if(errno == 11) cout << "no data to read!" << endl;}else if(recvLen == 0){cout << "server has close!" << endl;break; }else{buff[25] = '';cout << "client recv " << recvLen << " bytes, message is:" << buff << endl; }sleep(2);}close(sockFd);cout << "client will exit!" << endl;
}
Linux网络编程:recv的返回值相关推荐
- Linux多线程编程-线程函数返回值(返回简单数据类型)
引言 通过几个实验练习,学习线程之间连接的具体实现.下面列举了两个例子,一个是子线程返回简单数据类型:另一个是子线程返回复杂数据类型. 实现代码 子线程返回简单的数据类型 #include<st ...
- 网络编程_bind函数返回值
#define _WINSOCK_DEPRECATED_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include&l ...
- 【Linux网络编程】并发服务器之多线程模型
00. 目录 文章目录 00. 目录 01. 概述 02. 多线程服务器 03. 多线程服务器实现思路 04. 多线程服务器实现 05. 附录 01. 概述 服务器设计技术有很多,按使用的协议来分有 ...
- 【Linux网络编程】TCP网络编程中connect listen和accept三者之间的关系
00. 目录 文章目录 00. 目录 01. TCP服务端和客户端流程 02. connect函数 03. listen函数 04. 三次握手 05. accept函数 06. 附录 01. TCP服 ...
- 【Linux网络编程】TCP编程
00. 目录 文章目录 00. 目录 01. TCP概述 02. TCP特点 03. TCP中CS架构 04. TCP相关函数 05. TCP服务端示例 06. TCP客户端示例 07. 附录 01. ...
- 【Linux网络编程】组播
00. 目录 文章目录 00. 目录 01. 组播概述 02. 组播应用分类 03. 组播地址 04. 组播地址与 MAC 地址的关系 05. 套接字选项 06. 程序示例 07. 附录 01. 组播 ...
- Linux网络编程 | 定时事件 :Linux常见定时方法、定时器链表、空闲断开
文章目录 Linux定时方法 定时器链表 空闲断开 Linux定时方法 Linux中为我们提供了三种定时方法,分别是Socket超时选项,SIGALRM信号,I/O复用超时参数.下面一一对其进行介绍. ...
- Linux网络编程——黑马程序员笔记
01P-复习-Linux网络编程 02P-信号量生产者复习 03P-协议 协议: 一组规则. 04P-7层模型和4层模型及代表协议 分层模型结构: OSI七层模型: 物.数.网.传.会.表.应TCP/ ...
- Linux网络编程---I/O复用模型之epoll
https://blog.csdn.net/men_wen/article/details/53456474 Linux网络编程-I/O复用模型之epoll 1. epoll模型简介 epoll是Li ...
最新文章
- 《树莓派Python编程入门与实战》——3.5 关于Python交互式shell
- Shell编程(week4_day1)--技术流ken
- 2017年深度学习优化算法最新进展:改进SGD和Adam方法
- INVALID_HANDLE_VALUE的意思和用法
- C/C++中使用函数memset对int型数组赋值(0,-1,max,min)
- python已经取代了excel_Python已经取代Excel?网友:笑了
- 网络(6)-TCP/IP对拥塞控制、滑动窗口如何实现可靠性?
- 陆奇技术入局拼多多,拼多多能否摆脱“五环外”?
- Coursera, Big Data 3, Integration and Processing (week 1/2/3)
- 手机弹奏计算机音乐的软件,APP推荐:11款简单好用工具的APP,一定要懂!
- 去了一趟字节跳动,被怼了!
- Java多重选择switch
- 深度学习论文-Cyclical Learning Rates for Training Neural Networks
- 为了研究而玩:游戏分析的方法
- swoole 连接mysql_swoole教程:用swoole4操作mysql连接池之读写分离
- 【IoT】 产品设计:结构设计之PCB设计(三)
- 更多丰富内容,请转移至博主的个人博客——SeaDream乄造梦
- C++-鼠标操作大全
- 从0开始学Unity做SLG系列(GameFramework框架)
- 在Windows中安装MinGW-w64最新版本(目前12.1.0)