zoukankan      html  css  js  c++  java
  • 通信编程:Winsock 接口载入

    Winsock 编程接口

    Winsock 是 Windows 下网络编程的规范,该规范是 Windows 下得到广泛应用的、开放的、支持多种协议的网络编程接口。从 1991 年的 1.0 版到 1995 年的 2.0.8 版,经过不断完善并在 Intel、Microsoft、Sun、SGI、Informix、Novell 等公司的全力支持下,已成为 Windows 网络编程的事实上的标准。——百度百科

    通过 Winsock 编程接口就可以令多个应用程序通过网络来进行通信,Winsock 编程接口有 Winsock1 和 Winsock2 两个版本,目前主要使用 Winsock2 来进行开发。想要使用 Winsock2 库,就需要包含头文件来使用相关的 socket 函数和结构体,同时还要添加到 WS2_32.lib 的链接。

    #include <winsock2.h>
    #pragma comment(lib, "WS2_32")  // 链接到 WS2_32.lib
    

    Winsock 的载入和释放

    载入与释放操作

    每个基于 Winsock 开发的程序都需要载入对应版本的 Winsock DLL,这样才能使用 Winsock 提供的工具包。 想要载入 Winsock 库,需要使用 WSAStartup() 函数:

    int
    WSAAPI
    WSAStartup(
        _In_ WORD wVersionRequested,
        _Out_ LPWSADATA lpWSAData
        );
    
    参数 类型 数据类型 说明
    wVersionRequested 输入 WORD 指定要加载的 Winsock 版本
    lpWSAData 返回值 LPWSADATA 一个指向 WSADATA 结构的指针

    其中 wVersionRequested 参数有 2 个字节,高字节指定次版本号,低字节指定主版本号,一般来说使用 Winsock2 时高字节和低字节都是 2。建立这个参数时,可以使用 MAKEWORD(a, b) 宏。函数的返回值时 LPWSADATA 结构,里面存储了加载的库的版本相关信息。

    #define MAKEWORD(a, b)      ((WORD)(((BYTE)(((DWORD_PTR)(a)) & 0xff)) | ((WORD)((BYTE)(((DWORD_PTR)(b)) & 0xff))) << 8))
    

    想要释放 Winksock 库,可以使用 WSACleanup() 函数。

    int
    WSAAPI
    WSACleanup(
        void
        );
    

    CInitSock 类

    由于每次使用 Winksock 程序都需要载入 Winksock 库,因为从封装性的角度来考虑,可以封装一个工具类来专门载入和释放 Winksock 库。首先先简单介绍一下 C++ 面向对象编程的构造器和析构器,注意和 Java 不同的是 Java 的类不需要写析构器。

    函数 函数名 返回值 功能
    构造器 和类名相同 不需要用户显式调用,而是在创建对象时自动执行
    析构器 在类名前面加一个 “~” 符号 不需要程序员显式调用,而是在销毁对象时自动执行

    其实这个工具类只需要写构造器和析构器即可,其中构造器需要使用 MAKEWORD(a, b) 宏给一个 WORD 指定版本号,然后调用 WSAStartup() 函数载入 Winsock2 库。析构器则只需要调用 WSACleanup() 方法,目的就是在不需要使用 Winsock2 时自动把它释放掉。

    #include <winsock2.h>
    #pragma comment(lib, "WS2_32")  // 链接到 WS2_32.lib
    
    class CInitSock
    {
    public:
        /*CInitSock 的构造器*/
        CInitSock(BYTE minorVer = 2, BYTE majorVer = 2)
        {
            // 初始化WS2_32.dll
            WSADATA wsaData;
            WORD sockVersion = MAKEWORD(minorVer, majorVer);
            if (::WSAStartup(sockVersion, &wsaData) != 0)
            {
                exit(0);
            }
        }
    
        /*CInitSock 的析构器*/
        ~CInitSock()
        {
            ::WSACleanup();
        }
    };
    

    为了以后调用方便,这个工具类可以写在 initsock.h 头文件中。

    Winsock 寻址方式

    sockaddr_in 结构

    Winsock 是 Windows 下网络编程的规范,是支持多种协议的网络编程接口,因此编址也需要顾及不同的协议栈。Winsock 的第一个版本使用 sockaddr 结构来编址,里面的 sa_family 成员制定了使用的编址方式。而对于 TCP/ IP 协议栈,可以直接使用 sockaddr_in 结构。

    typedef struct sockaddr_in {
    
    #if(_WIN32_WINNT < 0x0600)
        short   sin_family;
    #else //(_WIN32_WINNT < 0x0600)
        ADDRESS_FAMILY sin_family;
    #endif //(_WIN32_WINNT < 0x0600)
    
        USHORT sin_port;
        IN_ADDR sin_addr;
        CHAR sin_zero[8];
    } SOCKADDR_IN, *PSOCKADDR_IN;
    

    其中有几个重要的成员:

    成员变量 说明
    sin_family 地址家族
    sin_port 端口号
    sin_addr IPv4 地址
    sin_zero[8] 占位,用于和 sockaddr 结构大小对齐

    其中对于 sin_family 变量必须使用 AF_INET 作为地址家族,表示使用 IP 编址。in_addr 结构用来存储 IP 地址,底层是使用一个共用体 union 来实现,可以用 4 个 uchar 或 2 个 ushort 或 1 个 ulong 来存储。

    typedef struct in_addr {
            union {
                    struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
                    struct { USHORT s_w1,s_w2; } S_un_w;
                    ULONG S_addr;
            } S_un;
    

    sockaddr_in 结构初始化

    因此对于 sockaddr_in 结构的初始化,实际上就是分别指定地址家族,绑定端口号和 IP 地址。

    sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(4567);
    sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    

    参考资料

    《Windows 网络与通信编程》,陈香凝 王烨阳 陈婷婷 张铮 编著,人民邮电出版社

  • 相关阅读:
    Shared Memory in Windows NT
    Layered Memory Management in Win32
    软件项目管理的75条建议
    Load pdbs when you need it
    Stray pointer 野指针
    About the Rebase and Bind operation in the production of software
    About "Serious Error: No RTTI Data"
    Realizing 4 GB of Address Space[MSDN]
    [bbk4397] 第1集 第一章 AMS介绍
    [bbk3204] 第67集 Chapter 17Monitoring and Detecting Lock Contention(00)
  • 原文地址:https://www.cnblogs.com/linfangnan/p/15383673.html
Copyright © 2011-2022 走看看