tcp包裹函数

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<strings.h>

void perr_exit(const char *s)
{
    perror(s);
    exit(-1);
}

int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
    int n;
again:
    if((n = accept(fd, sa, salenptr)) < 0)
    {
        if((errno == ECONNABORTED) || (errno == EINTR))//如果是被信号中断和软件层次中断,不能退出
            goto again;
        else
            perr_exit("accept error");
    }
    return n;
}

int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
    int n;
    
    if((n = bind(fd, sa, salen)) < 0)
        perr_exit("bind error");

    return n;
}

int Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
    int n;

    if((n = connect(fd, sa, salen)) < 0)
        perr_exit("connect error");

    return n;
}

int Listen(int fd, int backlog)
{
    int n;
    if((n = listen(fd, backlog)) < 0)
        perr_exit("listen error");

    return n;
}

int Socket(int family, int type, int protocal)
{
    int n;
    if((n = socket(family, type, protocal)) < 0)
        perr_exit("socket error");
    return n;
}

ssize_t Read(int fd, void *ptr, size_t nbytes)
{
    ssize_t n;

again:
    if((n = read(fd, ptr, nbytes)) == -1)
    {
        if(errno == EINTR)
            goto again;
        else
            return -1;
    }
    return n;
}

ssize_t Write(int fd, const void *ptr, size_t nbytes)
{
    ssize_t n;

again:
    if((n = write(fd, ptr, nbytes)) == -1)
    {
        if(errno == EINTR)
            goto again;
        else
            return -1;
    }
    return n;
}

// 读取固定的字节数数据
ssize_t Readn(int fd, void *vptr, size_t n)
{
    size_t nleft;   //unsigned int 剩余未读取的字节数
    ssize_t nread; //int 实际读到的字节数
    char *ptr;

    ptr = vptr;
    nleft = n;

    while(nleft > 0)
    {
        if((nread = read(fd, ptr, nleft)) < 0)
        {
            if(errno == EINTR)
                nread = 0;
            else
                return -1;
        }
        else if(nread == 0)
            break;
        
        nleft -= nread;
        ptr += nread;
    }
    return n - nleft;
}

// 从文件描述符中读取一个字符的函数
// 返回实际读取的字节数,出错时返回-1
static ssize_t my_read(int fd, char *ptr)
{
    static int read_cnt;
    static char *read_ptr;
    static char read_buf[100];

    // 如果缓冲区为空,重新从文件中读取数据
    if(read_cnt <= 0)
    {
again:
        // 调用read函数读取数据
        if((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0)
        {
            // 如果被中断,重新尝试读取
            if(errno == EINTR)
                goto again;
            return -1;
        }
        // 文件描述符被关闭,退出
        else if(read_cnt == 0)
            return 0;
        read_ptr = read_buf;
    }
    // 从缓冲区中读取一个字符
    read_cnt--;
    *ptr = *read_ptr++;
    return 1;
}

// 从文件描述符中读取一行数据的函数,限制最大长度为maxlen
// 返回实际读取的字节数,出错时返回-1
ssize_t Readline(int fd, void *vptr, size_t maxlen)
{
    ssize_t n, rc;
    char c, *ptr;
    ptr = vptr;

    // 循环读取每个字符,直到达到最大长度
    for(n = 1; n < maxlen; n++)
    {
        // 调用my_read函数读取一个字符
        if((rc = my_read(fd, &c)) == 1)
        {
            *ptr++ = c;
            // 如果读到换行符,结束循环
            if(c == '\n')
                break;
        }
        // 文件结束,将字符串结束符添加并返回实际读取的字节数
        else if(rc == 0)
        {
            *ptr = 0;
            return n-1;
        }
        // 出错时返回-1
        else
            return -1;
    }
    *ptr = 0;

    // 返回实际读取的字节数
    return n;
}

// 创建并绑定IPV4 TCP套接字,返回监听套接字描述符
// 参数:
//  - port:要绑定的端口号
//  - IP:要绑定的IP地址,如果为NULL,则绑定到所有可用的接口
// 返回值:监听套接字描述符
int tcp4bind(short port, const char *IP)
{
    struct sockaddr_in serv_addr; // 服务器地址结构体
    int lfd = Socket(AF_INET, SOCK_STREAM, 0); // 创建TCP套接字
    bzero(&serv_addr, sizeof(serv_addr)); // 将服务器地址结构体清零
    if(IP == NULL)
    {
        // 如果IP为空,则绑定到所有可用接口(0.0.0.0)
        serv_addr.sin_addr.s_addr = INADDR_ANY;
    }
    else
    {
        // 将IP地址从文本形式转换为网络字节序
        if(inet_pton(AF_INET, IP, &serv_addr.sin_addr.s_addr) <= 0)
        {
            perror(IP); // 转换失败
            exit(1); // 退出程序
        }
    }
    serv_addr.sin_family = AF_INET; // 地址族为IPv4
    serv_addr.sin_port = htons(port); // 设置端口号并转换为网络字节序

    // 设置套接字选项,可选,用于地址重用
    // int opt = 1;
    //setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    // 将套接字绑定到指定地址和端口
    Bind(lfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    return lfd; // 返回监听套接字描述符
}

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值