zoukankan      html  css  js  c++  java
  • [转]winsock和winsock2冲突

    [转]winsock和winsock2冲突

    出处:不详

    在初学Windows网络编程时,曾经遇到过两类编译错误(VC6的Build窗口哗哗的显示了102个Errors),都是些类型未定义或者重复定义问 题,让我感到很郁闷。这两种错误情况下的第一条错误信息分别为:

    错误情形1:mswsock.h(69) : error C2065: 'SOCKET' : undeclared identifier

    错误情形2:winsock2.h(99) : error C2011: 'fd_set' : 'struct' type redefinition

    后来,我静下心来仔细分析一下错误提示及相 关文件,终于找到了原因。我们知道,Windows网络编程至少需要两个头文件:winsock2.h和windows.h,而在 WinSock2.0之前还存在一个老版本的winsock.h。正是这三个头文件的包含顺序,导致了上述问题的出现。先让我们看看 winsock2.h的内容,在文件开头有如下宏定义:

    #ifndef _WINSOCK2API_
    #define _WINSOCK2API_
    #define _WINSOCKAPI_    /* Prevent inclusion of winsock.h in windows.h */


    WINSOCK2API_ 很容易理解,这是最常见的防止头文件重复包含的保护措施。_WINSOCKAPI_的定义则是为了阻止对老文件winsock.h的包含,即是说,如果用 户先包含了winsock2.h就不允许再包含winsock.h了,否则会导致类型重复定义。这是怎样做到的呢?很简单,因为winsock.h的头部 同样存在如下的保护措施:

    #ifndef _WINSOCKAPI_
    #define _WINSOCKAPI_


    再 回过头来看winsock2.h,在上述内容之后紧跟着如下宏指令:

    /*
    * Pull in WINDOWS.H if necessary
     
    */
     
    #ifndef _INC_WINDOWS
     
    #include <windows.h>
     
    #endif /* _INC_WINDOWS */
     

    其作用是如果用户没有包含 windows.h(_INC_WINDOWS在windows.h中定义)就自动包含它,以定义WinSock2.0所需的类型和常量等。

    现在切换到windows.h,查找winsock,我们会惊奇的发现以下内容:

    #ifndef WIN32_LEAN_AND_MEAN
    #include <cderr.h>
    #include <dde.h>
    #include <ddeml.h>
    #include <dlgs.h>
    #ifndef _MAC
    #include <lzexpand.h>
    #include <mmsystem.h>
    #include <nb30.h>
    #include <rpc.h>
    #endif
    #include <shellapi.h>
    #ifndef _MAC
    #include <winperf.h> 
    #if(_WIN32_WINNT >= 0x0400)
    #include <winsock2.h>
    #include <mswsock.h>
    #else
    #include <winsock.h>
    #endif /* _WIN32_WINNT >=   0x0400 */
    #endif

    // 这里省略掉一部分内容
    #endif /* WIN32_LEAN_AND_MEAN */


    看到没?windows.h 会反向包含winsock2.h或者winsock.h!相互间的包含便是万恶之源!

    下面具体分析一下问题是怎么发生的。

    错 误情形1:我们在自己的工程中先包含winsock2.h再包含windows.h,如果WIN32_LEAN_AND_MEAN未定义且 _WIN32_WINNT大于或等于0x400,那么windows.h会在winsock2.h开头被自动引入,而windows.h又会自动引入 mswsock.h,此时,mswsock.h里所用的socket类型还尚未定义,因此会出现类型未定义错误。
    错误情形2:先包含 windows.h再包含winsock2.h,如果WIN32_LEAN_AND_MEAN未定义且_WIN32_WINNT未定义或者其版本号小于 0x400,那么windows.h会自动导入旧有的winsock.h,这样再当winsock2.h被包含时便会引起重定义。

    这里要 说明的是,宏WIN32_LEAN_AND_MEAN的作用是减小win32头文件尺寸以加快编译速度,一般由AppWizard在stdafx.h中自 动定义。_WIN32_WINNT的作用是开启高版本操作系统下的特殊函数,比如要使用可等待定时器(WaitableTimer),就得要求 _WIN32_WINNT的值大于或等于0x400。因此,如果你没有遇到上述两个问题,很可能是你没有在这些条件下进行网络编程。
    问题还没有结束,要知道除了VC自带windows库文件外,MS的Platform SDK也含有这些头文件。我们很可能发现在之前能够好好编译的程序在改变了windows头文件包含路径后又出了问题。原因很简单,Platform SDK中的windows.h与VC自带的文件存在差异,其相同位置的代码如下:

    #ifndef WIN32_LEAN_AND_MEAN
    #include <cderr.h>
    #include <dde.h>
    #include <ddeml.h>
    #include <dlgs.h>
    #ifndef _MAC
    #include <lzexpand.h>
    #include <mmsystem.h>
    #include <nb30.h>
    #include <rpc.h>
    #endif
    #include <shellapi.h>
    #ifndef _MAC
    #include <winperf.h>
    #include <winsock.h>   // 这里直接包含winsock.h
    #endif
    #ifndef NOCRYPT
    #include <wincrypt.h>
    #include <winefs.h>
    #include <winscard.h>
    #endif 
    #ifndef NOGDI
    #ifndef _MAC
    #include <winspool.h>
    #ifdef INC_OLE1
    #include <ole.h>
    #else
    #include <ole2.h>
    #endif /* !INC_OLE1 */
    #endif /* !MAC */
    #include <commdlg.h>
    #endif /* !NOGDI */
    #endif /* WIN32_LEAN_AND_MEAN */


    唉,我们不禁要问MS为什么要搞这么多花样,更让人气愤的是,既然代码不一 样,windows.h里却没有任何一个宏定义能够帮助程序辨别当前使用的文件是VC自带的还是PSDK里的。

    后来,我写了一个头文件专 门处理winsock2.h的包含问题,名为winsock2i.h,只需在要使用WinSock2.0的源文件里第一个包含此文件即可,不过由于前面提 到的问题,当使用PSDK时,需要手工定义一下USING_WIN_PSDK,源码如下:

    //
    // winsock2i.h - Include winsock2.h safely.
    //
    // Copyleft   02/24/2005   by freefalcon
    //
    //
    // When WIN32_LEAN_AND_MEAN is not defined and _WIN32_WINNT is LESS THAN 0x400,
    // if we include winsock2.h AFTER windows.h or winsock.h, we get some compiling
    // errors as following:
    //    winsock2.h(99) : error C2011: 'fd_set' : 'struct' type redefinition
    // 
    // When WIN32_LEAN_AND_MEAN is not defined and _WIN32_WINNT is NOT LESS THAN 0x400,
    // if we include winsock2.h BEFORE windows.h, we get some other compiling errors:
    //    mswsock.h(69) : error C2065: 'SOCKET' : undeclared identifier
    // 
    // So, this file is used to help us to include winsock2.h safely, it should be 
    // placed before any other header files.
    // 
    #ifndef _WINSOCK2API_
    // Prevent inclusion of winsock.h
    #ifdef _WINSOCKAPI_
    #error Header winsock.h is included unexpectedly.
    #endif
    // NOTE: If you use Windows Platform SDK, you should enable following definition:
    // #define USING_WIN_PSDK
    #if !defined(WIN32_LEAN_AND_MEAN) && (_WIN32_WINNT >= 0x0400) && !defined(USING_WIN_PSDK)
    #include <windows.h>
    #else
    #include <winsock2.h>
    #endif
    #endif//_WINSOCK2API_

  • 相关阅读:
    SharePoint 2010 User Profile Sync Service自动停止
    如何区别多个svchost.exe?
    Log Parser分析IIS log的一个简单例子
    Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.
    Windows中右键点击文件夹, 结果找不到共享选项卡, 怎么办?
    介绍SOS中的SaveModule命令
    SharePoint中Draft版本的文档不会收到document added的Alert Email
    和我一起学Windows Workflow Foundation(1)创建和调试一个WF实例
    门户网站
    C#基础—— check、lock、using语句归纳
  • 原文地址:https://www.cnblogs.com/winkyao/p/2379273.html
Copyright © 2011-2022 走看看