码迷,mamicode.com
首页 > 其他好文 > 详细

TCP之函数封装

时间:2014-10-16 00:18:31      阅读:295      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   io   os   ar   for   文件   

本文所有函数皆是为实现 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);//发送一个int
int32_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,本次发送数据的真实长度val
void 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之函数封装

标签:style   blog   http   color   io   os   ar   for   文件   

原文地址:http://www.cnblogs.com/xfxu/p/4027460.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!