[原]C语言安利一波函数封装

刘生玺 18/08/23 16:45:01

   最近学弟学妹们在写聊天室,期间遇到了很多问题,也“逼迫”我们这些大二(其实即将大三)狗考虑了许多以前没有考虑过的东西。现在就着我们小组的聊天室的项目,送给学弟学妹们”几个可能安全的封装函数。“

frist : 保证发送“len”字节到套接字

ssize_t Sendlen(int fd, const void *buf, size_t len, int flags)
{
    ssize_t n = 0;
    size_t sum = 0;
    const char *ptr;
    ptr = (const char *)buf;
    while (sum < len)
    {
        n = send(fd, (void *)ptr, len - sum, flags);
        if (n < 0)
        {
            if (errno == EINTR)
                n = 0;
            else
                err_sys("send error ", __LINE__);
        }
        sum += n;
        ptr += n;
    }
    return (sum);
}

second:保证接受“len”字节到套接字

ssize_t Recvlen(int fd, void *buf, size_t len, int flags) 
{
    ssize_t n = 0;
    size_t sum = 0;
    const char *ptr;
    ptr = buf;
    while (sum < len)
    {
        n = recv(fd, (void *)ptr, len - sum, flags);
        if (n < 0)
        {
            if (errno == EINTR)
                n = 0;
            else
                err_sys("recv error ", __LINE__);
        }
        else if (n == 0)
        {
            printf("对端连接关闭!!!\n");
            break;
        }
        sum += n;
        ptr += n;
    }
    return (sum);
}

thrid:从套接字读取一行数据

static int recv_cnt = 0;
static char *recv_ptr = NULL;
static char recv_buf[MAXLINE];

static ssize_t my_recv(int fd, char *ptr, int flags)
{
    if (recv_cnt <= 0)
    {
    again:
        if ((recv_cnt = recv(fd, recv_buf, sizeof(recv_buf), flags)) < 0)
        {
            if (errno == EINTR)
                goto again;
            else
                return (-1);
        }
        else if (recv_cnt == 0)
        {
            return (0);
        }
        recv_ptr = recv_buf;
    }
    recv_cnt--;
    *ptr = *recv_ptr++;
    return (1);
}
ssize_t recvline(int fd, void *vptr, size_t maxlen, int flags)
{
    ssize_t n, rc;
    char c, *ptr;
    ptr = vptr;
    for (n = 1; n < maxlen; n++)
    {
        if ((rc = my_recv(fd, &c, flags)) == 1)
        {
            *ptr++ = c;
            if (c == '\n')
                break;
        }
        else if (rc == 0)
        {
            *ptr = 0;
            return (n - 1);
        }
        else
            return (-1);
    }
    *ptr = 0;
    return (n);
}
ssize_t Recvline(int fd, void *buf, size_t Maxlen, int flags)
{ //注意参数 Maxlen
    ssize_t n;
    if ((n = recvline(fd, buf, Maxlen, flags)) < 0)
        err_sys("recvline error ", __LINE__);
    return (n);
}

注意事项:

send和recv有三个要点:

1. 在每次进行send或者recv时,第二个参数是随着读取的字节数量而改变的。

2. 传进来的第二个参数是 void *的类型,给他加1减1,就会出现问题。必须首先转换为char *

3. 第三个参数len。同上,也是需要随着读取的字节数而改变

recvline

static int recv_cnt = 0; //读取的数据量
static char *recv_ptr = NULL; //指向recv_buf的字节型指针
static char recv_buf[MAXLINE]; //存放读取数据的结构

recvline 函数从recv_buf中拿到一行数据 。
my_recv函数检查如果读取的数据量 <=0,就进行一次读取。问:这里为什么要用recv而不用自己封装的 Recvlen? 因为Recvlen直到读取len个字节才会返回,而我们这里并不要求,只要读取从缓冲区中读取比MAXLINE小的字节就行了 。

if (recv_cnt <= 0)
    {
again:
        if ((recv_cnt = recv(fd, recv_buf, sizeof(recv_buf), flags)) < 0)
        {
            if (errno == EINTR)
                goto again;
            else
                return (-1);
        }
        else if (recv_cnt == 0)
        {
            return (0);
        }
        recv_ptr = recv_buf;
    }

bug:考虑到多线程,多进程,在循环send或者recv时应该加上锁,不然万一有两个线程往同一个套接字发送数据,而时间片又进行了转换了,就会造成错乱,保证不了完整的发送一个结构体数据了。

作者:liushengxi_root 发表于 2018/08/23 16:45:01 原文链接 https://blog.csdn.net/liushengxi_root/article/details/81981600
阅读:43 评论:1 查看评论