1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 网络通信防止connect accept rend write阻塞设置超时处理

网络通信防止connect accept rend write阻塞设置超时处理

时间:2019-10-30 17:00:58

相关推荐

网络通信防止connect accept rend write阻塞设置超时处理

为了防止connect,accept,rend,write阻塞在哪影响效率问题,我们设置一个认可超时时间处理,通过调用系统内核函数帮我检查读写缓冲区是个有数据可读,

分析场景: 内核去维护一个双向读写缓冲区 类似乳滑动窗口,

.发送端快速发送消息到到接收端,而接收端处理消息不及时,故接收端内核读缓冲区快满了,此时发送端send就会阻塞,

read读超时设置:

int readTimeOut(int cfd, int timeOut ){//我们不知道内核的读缓冲区是否有数据到达,所有我们委托内核去检查读缓冲区//类似内核去检查的 io多路转发 函数有 eppol select eppol_wait//我这里暂时用select 去检查 他是跨平台的fd_set fdread;FD_ZERO(&fdread);FD_SET(cfd, &fdread);struct timeval val;val.tv_sec = timeOut;val.tv_usec = 0;int ret = 0;while (1){ret = select(cfd+1, &fdread, NULL, NULL, &val);if (ret == 0 && errno == EINTR) //此时标识外部信号中终端了,允许再超时一次继续监测{continue;}else{//有数据或异常break;}}; //if (ret == 0){//此时标识已经超时了 内核读缓冲区没有数据可读,没必要调用recv阻塞在这}else if(ret > 0){//char buf[1024] = {0};int len = recv(cfd, buf, sizeof(buf), 0); //此时调用recv一定不阻塞 不需要等待return ret;}else{if(ret == -1 && errno == EAGIN) //标识数据已经读完了{printf("表叔数据已经读完了\n");}ret = errno;return -1;}}

write写超时设置

int writeTimeOut(int fd, int timeOut){//通过select 委托内核检测写缓冲区是否可写fd_set fdwirte;FD_ZERO(&fdwirte);FD_SET(fd, &fdwirte);int ret = 0;struct timeval val;val.tv_sec = timeOut;val.tv_usec = 0;while (1) //{ret = select(fd+1, NULL, &fdwirte, NULL, &val); //设置超时时间if (ret == 0 && errno == EINTR) //标识信号中断允许再超时一次{continue;}else{break;}}if (ret == 0){//已经超时了表明写缓冲区已经满了 不可写return -1;}else if(ret > 0){//可写char* p = "hell world"send(fd, p, strlen(p)); //此时send一定不阻塞}else{//ret = errno;return-1;}}

accept接受新的客户端设置超时处理

int acceptTimeOut(int lfd, int timeOut){//委托内核去检测监听描述符的读缓冲区是个可读fd_set fdread;FD_ZERO(&fdread);FD_SET(lfd, &fdread);int ret = 0;struct timeval val;val.tv_sec = timeOut;val.tv_usec = 0;while (1){ret = select(lfd+1, &fdread, NULL, NULL, &val); //设置超时if (ret == 0 && errno == EINTR) //信号中断再超时一次{continue;}else{break;}}if (ret == 0){//超时//处理其他的业务}else if(ret > 0){//struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(8989);addr.sin_addr.s_addr = INADDR_ANY;int len = sizeof(addr);ret = accept(lfd, (struct sockaddr*)&addr, &len); //此时 accept 一定不阻塞if (ret == -1){ret = errno;return ret;}//}else{//}}

connect连续服务器设置超时处理

int connectTimeOut(int cfd, int timeOut){//连接的是是个不是是否连接成功不阻塞设置为非阻塞int flag = fcntl(cfd, F_GETFL);flag |= O_NONBLOCK;fcntl(cfd, F_SETFL, flag);struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(8989);inet_pton(AF_INET, "192.168.0.1", &addr.sin_addr.s_addr);int ret = connect(cfd, (struct sockaddr*)&addr, sizeof(addr)); ////当我们以非阻塞的方式来进行连接的时候,返回的结果如果是 -1,// 这并不代表这次连接发生了错误,如果它的返回结果是 EINPROGRESS,// 那么就代表连接还在进行中。 后面可以通过poll或者select来判断socket是否可写,// 如果可以写,说明连接完成了。if (ret < 0 && errno == EINPROGRESS) {fd_set fdwrite;FD_ZERO(&fdwrite);FD_SET(cfd, &fdwrite);int ret = 0;struct timeval val;val.tv_sec = timeOut;val.tv_usec = 0;while (1){ret = select(cfd+1, NULL, &fdwrite, NULL, &val);if (ret < 0 && errno == EINTR){continue;}else{break;}}if (ret == 0) //连接超时了{errno = ETIMEDOUT;return -1;}else if(ret > 0) //连接已经成功了{/* ret返回为1(表示套接字可写),可能有两种情况,一种是连接建立成功,一种是套接字产生错误,*//* 此时错误信息不会保存至errno变量中,因此,需要调用getsockopt来获取。 */int err = 0;int errLen = sizeof(err);//获取cfd描述符状态int sockoptret = getsockopt(cfd, SOL_SOCKET, SO_ERROR, &err, &errLen);if (sockoptret < 0) //连接错误了{errno = err;return -1;} else //连接成功{//return 0;}}}//连接一次完成后将 原先设置的非阻塞的 去掉还原int falg = fcntl(cfd, F_GETFL);falg &= (~O_NONBLOCK);fcntl(cfd, F_SETFL, falg);}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。