首页 > 代码库 > TCP之函数封装
TCP之函数封装
本文所有函数皆是为实现 TCP之简单回传(二) 系列所封装的函数;
所有函数皆用C语言实现。函数以及注释如下:
头文件:
//.h#ifndef SYSUTIL_H#define SYSUTIL_H#include <stdint.h>#include <sys/types.h>void nano_sleep(double val); //实现定时作用ssize_t readn(int fd, void *buf, size_t count);//读取真实数据ssize_t writen(int fd, const void *buf, size_t count);//写所读来的数据ssize_t readline(int fd, void *usrbuf, size_t maxlen);//读数据(解决粘包问题)ssize_t readline_slow(int fd, void *usrbuf, size_t maxlen);//读数据--->效率低下void send_int32(int sockfd, int32_t val);//发送一个intint32_t recv_int32(int sockfd); //接收一个int 为后来的readn读入精准的数据做准备#endif
具体实现:
/.c#include "sysutil.h"#include <stdint.h>#include <stddef.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#include <errno.h>#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); }while(0)//睡眠时间void nano_sleep(double val){ struct timespec tv; memset(&tv, 0, sizeof(tv)); tv.tv_sec = val;//取整 tv.tv_nsec = (val- tv.tv_sec)*1000*1000*1000; int ret; do { ret = nanosleep(&tv, &tv); }while(ret == -1 && errno ==EINTR);//若是被中断信号打断,则继续执行sleep }//告诉server,本次发送数据的真实长度valvoid send_int32(int sockfd, int32_t val){ int32_t tmp = htonl(val);//转化为网络字节序 if(writen(sockfd, &tmp, sizeof(int32_t)) != sizeof(int32_t))//发送给server ERR_EXIT("write");}//接收一个int型数据,以确保精确接收int32_t recv_int32(int sockfd){ int32_t tmp; if(readn(sockfd, &tmp, sizeof(int32_t))!= sizeof(int32_t)) ERR_EXIT("read"); return ntohl(tmp);//网络序转化为主机序。}//server读取数据ssize_t readn(int fd, void *buf, size_t count){ size_t nleft = count; //剩余字符数 ssize_t nread;//用于返回值 char *pbuf = (char*)buf; while(nleft > 0) { nread = read(fd, pbuf, nleft);//发送数据 if( nread == -1) { if(errno == EINTR)//被中断信号打断 continue; return -1 ; //err }else if( nread == 0) { break; //读完 } nleft = nleft - nread;//剩余字符数 pbuf = pbuf + nread;//下次的偏移位置 } return (count-nleft) ;//attentin 两个条件退出循环}//client向server写数据ssize_t writen(int fd, const void* buf, size_t count){ size_t nleft = count ;//剩余字节流 ssize_t nwrite;//return const char *pbuf =(const char*)buf; while(nleft > 0) { nwrite = write( fd, pbuf, nleft);//写数据 if(nwrite <= 0)//err { if(nwrite == -1 && errno == EINTR) continue; return -1; } nleft = nleft - nwrite;//剩余字节流 pbuf = pbuf + nwrite;//偏移位置 } return count;}//预览内核缓冲区数据ssize_t recv_peek(int fd, void *usrbuf, size_t maxlen){ ssize_t nread; do { nread = recv(fd, usrbuf, maxlen, MSG_PEEK); } while(nread == -1 && errno == EINTR); return nread;}ssize_t readline(int fd, void *usrbuf, size_t maxlen){ char *bufp = (char *)usrbuf; size_t nleft = maxlen - 1; ssize_t count = 0; ssize_t nread; while(nleft > 0) { nread = recv_peek(fd, bufp, nleft);//预览内核缓冲区数据 if( nread <= 0) //由客户端处理 return nread; //遍历bufp,以确定是否存在\n int i; for ( i = 0; i < nread; i++) { //存在‘\n‘ if(bufp[i] == ‘\n‘) { size_t nsize = i +1; if( readn(fd, bufp, nsize) != nsize)//说明\n前有i个字符 ERR_EXIT("readn"); bufp +=nsize; //重置偏移量 count +=nsize;//统计读取个数 *bufp = 0; return count; } } //不存在‘\n‘ if( readn(fd, bufp, nread) != nread) ERR_EXIT("readn"); bufp += nread; count += nread; nleft -=nread; } *bufp = 0; return count;}//按字符读取--->由于每读取一个字符就产生一次系统调用,故效率较低ssize_t readline_slow(int fd, void *usrbuf, size_t maxlen){ char *bufp = (char*)usrbuf;//偏移位置 ssize_t nread; size_t nleft = maxlen -1 ;//剩余字节数 char ch;//保存每次读取的字符 while( nleft > 0)//只要还有没读的,就一直循环 { if(-1 == (nread=read(fd, &ch, 1)))//把从fd中读取的字符存进ch中 { if(errno == EINTR)//被中断信号打断 continue; return -1;//err }else if(0 == nread ) break; //EOF *bufp = ch;//将读取的字符存进buf bufp++;//向前移动 nleft --;//剩余字节数-- if(ch == ‘\n‘)//如果该字符为\n。本次读取完成 break; } *bufp =‘\0‘;// return (maxlen- nleft -1);//最大长度 -剩余的字符 - ‘\0‘}
TCP之函数封装
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。