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

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

在套接口中,一个套接字只是用户程序与内核交互信息的枢纽,它自身没有太多的信息,也没有网络协议地址和 端口号等信息,在进行网络通信的时候,必须把一个套接字与一个地址相关联,这个过程就是地址绑定的过程。许多时候内核会我们自动绑定一个地址,然而有时用 户可能需要自己来完成这个绑定的过程,以满足实际应用的需要,最典型的情况是一个服务器进程需要绑定一个众所周知的地址或端口以等待客户来连接。这个事由 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;
}
你列出的是 `x86_64-w64-mingw32` 工具链在 Ubuntu 上安装后提供的完整命令集合,这些工具来自 **MinGW-w64** 的 GCC 编译器套件,用于交叉编译 Windows 程序(64 位)。 下面我将 **逐一解释这些命令的用途和区别**,并说明如何正确使用它们来构建 C/C++ 程序。 --- ## 🧰 MinGW-w64 工具链详解(针对 `x86_64-w64-mingw32`) ### ✅ 基本命名规则 格式为: ``` <target-triplet>-<tool-name>[-(posix|win32)] ``` - `x86_64-w64-mingw32`: 目标平台三元组 - 架构:x86_64(64位) - 供应商:w64(支持 Win64 的 MinGW 分支) - 系统:Windows - `posix` / `win32`: 表示线程模型或异常处理方式 - `posix`: 使用 POSIX 风格的线程和异常处理(推荐,更现代、稳定) - `win32`: 使用 Windows 原生线程模型(旧版兼容) > ⚠️ 如果没有后缀,默认行为取决于你的系统配置。通常建议使用 `-posix` 版本。 --- ## 🔍 各命令详细说明 | 命令 | 作用 | 推荐使用 | |------|------|----------| | `x86_64-w64-mingw32-gcc` | C 编译器(主入口) | ✅ 是 | | `x86_64-w64-mingw32-g++` | C++ 编译器(主入口) | ✅ 是 | | `x86_64-w64-mingw32-gcc-posix` | 使用 POSIX 线程模型的 GCC | ✅ 强烈推荐 | | `x86_64-w64-mingw32-g++-posix` | 使用 POSIX 线程模型的 G++ | ✅ 强烈推荐 | | `x86_64-w64-mingw32-gcc-win32` | 使用 Win32 线程模型的 GCC | ❌ 不推荐(易崩溃) | | `x86_64-w64-mingw32-g++-win32` | 使用 Win32 线程模型的 G++ | ❌ 不推荐 | 📌 **最佳实践:优先使用 `-posix` 结尾的版本** ```bash # 推荐写法(C++) x86_64-w64-mingw32-g++-posix -static -o myapp.exe main.cpp # 或简写(如果软链接已设置) x86_64-w64-mingw32-g++ -static -o myapp.exe main.cpp ``` --- ### 🛠 辅助工具说明 | 命令 | 作用 | |------|------| | `x86_64-w64-mingw32-gcc-ar` / `...-ar-posix` / `...-ar-win32` | 归档工具,打包静态库 `.a` 文件(相当于 Linux 的 ar) | | `x86_64-w64-mingw32-gcc-ranlib` / `...-ranlib-posix` / `...-ranlib-win32` | 为静态库生成索引(提高链接速度) | | `x86_64-w64-mingw32-gcc-nm` / `...-nm-posix` / `...-nm-win32` | 查看目标文件符号表(调试用) | | `x86_64-w64-mingw32-gcc-dumpmachine` | 输出目标机器类型(调试工具链时有用) | | `x86_64-w64-mingw32-gcov` / `...-gcov-dump` / `...-gcov-tool` | 代码覆盖率分析工具(配合 `-fprofile-arcs -ftest-coverage` 使用) | | `x86_64-w64-mingw32-gprof` | 性能分析工具(需编译时加 `-pg`) | --- ### 📦 示例:编译一个简单的 C++ 程序 #### 创建 `main.cpp` ```cpp #include <iostream> using namespace std; int main() { cout << "Hello from MinGW-w64 on Linux!" << endl; return 0; } ``` #### 使用推荐工具编译 ```bash x86_64-w64-mingw32-g++-posix -static -s -o hello.exe main.cpp ``` 参数说明: - `-static`: 静态链接运行时库,避免依赖 `libstdc++-6.dll` 等 - `-s`: strip 符号信息,减小体积 - `-o hello.exe`: 输出 Windows 可执行文件 #### 检查输出 ```bash file hello.exe ``` 输出应为: ``` hello.exe: PE32+ executable (console) x86-64, for MS Windows ``` --- ### 💡 如何选择正确的工具? | 场景 | 推荐命令 | |------|---------| | 编译普通 C 程序 | `x86_64-w64-mingw32-gcc-posix` | | 编译 C++ 程序 | `x86_64-w64-mingw32-g++-posix` | | 创建静态库 | `x86_64-w64-mingw32-gcc-ar-posix` | | 查看符号 | `x86_64-w64-mingw32-gcc-nm` | | 调试覆盖率 | `x86_64-w64-mingw32-gcov` | > 实际上,大多数情况下你可以直接使用不带后缀的 `g++` 或 `gcc`,因为它们通常是符号链接到 `-posix` 版本。 你可以检查一下: ```bash ls -l $(which x86_64-w64-mingw32-g++) ``` 很可能指向 `x86_64-w64-mingw32-g++-posix` --- ### ⚠️ 注意事项 1. **不要混用 `posix` 和 `win32` 编译的对象文件** 它们使用不同的异常处理机制(SEH vs SJLJ),混合会导致运行时崩溃。 2. **推荐始终使用 `-static` 编译 GUI 程序** 避免用户缺少 MinGW 运行时 DLL。 3. **Qt 程序必须使用与 Qt 构建时一致的线程模型** 若 Qt 是用 `posix` 编译的,则你也必须用 `g++-posix` 编译你的程序。 --- ### ✅ 总结:你应该怎么用? ```bash # ✅ 推荐做法(C++) x86_64-w64-mingw32-g++-posix -static -O2 -s -o app.exe main.cpp # 或者简写(等效) x86_64-w64-mingw32-g++ -static -O2 -s -o app.exe main.cpp ``` 只要确保你的工具链默认使用的是 `posix` 模型即可。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值