posix_quic-master 服务器端bind()函数

博客介绍了套接字在网络通信中需与地址关联,即地址绑定过程,有时需用户手动完成,由bind函数实现。还说明了bind函数的参数与返回值,参数包括指定套接字的sockfd、指定地址的addr和确定复制数据量的addrlen,最后给出了相关代码跟进示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在套接口中,一个套接字只是用户程序与内核交互信息的枢纽,它自身没有太多的信息,也没有网络协议地址和 端口号等信息,在进行网络通信的时候,必须把一个套接字与一个地址相关联,这个过程就是地址绑定的过程。许多时候内核会我们自动绑定一个地址,然而有时用 户可能需要自己来完成这个绑定的过程,以满足实际应用的需要,最典型的情况是一个服务器进程需要绑定一个众所周知的地址或端口以等待客户来连接。这个事由 bind的函数完成。

从bind函数功能我们很容易推测出这个函数的需要的参数与相应的返回值,如果此时大家已经对socket接口有点熟悉了:

#include<sys/socket.h>
int bind( int sockfd, struct sockaddr* addr, socklen_t addrlen)
返回:0 ──成功, - 1 ──失败
参数sockfd
指定地址与哪个套接字绑定,这是一个由之前的socket函数调用返回的套接字。调用bind的函数之后,该套接字与一个相应的地址关联,发送到这个地址的数据可以通过这个套接字来读取与使用。
参数addr
指定地址。这是一个地址结构,并且是一个已经经过填写的有效的地址结构。调用bind之后这个地址与参数sockfd指定的套接字关联,从而实现上面所说的效果。
参数addrlen
正如大多数socket接口一样,内核不关心地址结构,当它复制或传递地址给驱动的时候,它依据这个值来确定需要复制多少数据。这已经成为socket接口中最常见的参数之一了。
下面来看代码 先初始化地址

//初始化地址
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(9700);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");

然后将这些参数传入

res = QuicBind(socket, (struct sockaddr*)&addr, sizeof(addr));

//判断返回值是正还是负

 CHECK_RES(res, "epoll_ctl");

跟踪一个这个CHECK_RES函数

#define CHECK_RES(res, api) \
    do {\
        if (res < 0) {\//如果返回值小于0就报错
            perror(api " error");\
            return 1;\
        }\
    } while (0)

下面跟踪一下这个QuicBind()函数

int QuicBind(QuicSocket sock, const struct sockaddr* addr, socklen_t addrlen)
{
    auto socket = EntryBase::GetFdManager().Get(sock);
    if (!socket || socket->Category() != EntryCategory::Socket) {
        DebugPrint(dbg_api, "sock = %d, return = -1, errno = EBADF", sock);
        errno = EBADF;
        return -1;
    }

    int res = ((QuicSocketEntry*)socket.get())->Bind(addr, addrlen);
    DebugPrint(dbg_api, "sock = %d, return = %d, errno = %d", sock, res, errno);
    return res;
}

//找到这个Bind(addr, addrlen)函数

 int QuicSocketEntry::Bind(const struct sockaddr* addr, socklen_t addrlen)
{
    switch (socketState_) {
        case QuicSocketState_None:
            {
                int res = CreateNewUdpSocket();
                if (res < 0) return -1;
            }

        case QuicSocketState_Inited:
            {
               int res = ::bind(*udpSocket_, addr, addrlen);
               if (res == 0)
                   socketState_ = QuicSocketState_Binded;
               return res;
            }

        default:
            errno = EINVAL;
            return -1;
    }
}

跟进CreateNewUdpSocket()

int QuicSocketEntry::CreateNewUdpSocket()
{
    if (udpSocket_) {
        errno = EINVAL;
        return -1;
    }

    int fd = ::socket(AF_INET, SOCK_DGRAM, 0);
    if (fd == -1) return -1;

    return SetUdpSocket(fd);
}

跟进这个SetUdpSocket(fd)

int QuicSocketEntry::SetUdpSocket(int fd)
{
    if (udpSocket_) {
        errno = EINVAL;
        return -1;
    }

    int val = ::fcntl(fd, F_GETFL, 0);
    if (val == -1) {
        ::close(fd);
        return -1;
    }
    int res = ::fcntl(fd, F_SETFL, val | O_NONBLOCK);
    if (res == -1) {
        ::close(fd);
        return -1;
    }

    val = GetOpt(sockopt_udp_rmem);
    if (!val) val = kDefaultUdpRecvMem;
    res = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&val, sizeof(int));
    if (res == -1) {
        ::close(fd);
        return -1;
    }

    val = GetOpt(sockopt_udp_wmem);
    if (!val) val = kDefaultUdpWriteMem;
    res = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char*)&val, sizeof(int));
    if (res == -1) {
        ::close(fd);
        return -1;
    }

    udpSocket_.reset(new int(fd), [](int* p){
                ::close(*p);
                delete p;
            });
    socketState_ = QuicSocketState_Inited;
    GetConnectionManager().Put(*udpSocket_, impl_->connection_id(), Fd(), true);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值