首页 > 代码库 > 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之函数封装