C++封装的socket库,浩大如ACE小巧如asio。有些东西如果不亲自走一遭的话,可能到最后也只能是掌握其表。所以开始艰难的旅程吧。

每一个winsock应用都必须首先加载winsock DLL的相应版本。如果在调用winsock之前没有加载winsock库,这个函数会返回一个SOCKET_ERROR。错误信息是WSANOTINITIALISED。winsock的初始化是通过下面这个函数进行的:

intWSAStartup(

              WORD wVersionRequested,      //<版本,高位代表副版本,低位代表高版本

              LPWSADATA lpWSAData //< 保存与库版本有关的信息

)

当你请求的版本大于等于机器上安装的winsock支持的最低版本的时候(例如:机器上安装的最低版本为1.1,如果你请求的是2.2,那么函数将成功。但是加载的版本未必是你请求的2.2版本。可以通过lpWSAData中的wVersion 来知道系统提供给你使用的版本)函数调用成功将返回一个0值,如果失败会返回出错代码。不需要通过WSAGetlastError来获得出错信息。

针对每一个成功的WSAStartup调用,都必须调用WSAClean来进行清理。应用程序中可能会多次调用WSAStartup(比如在某处需要获得机器上winsock的信息),那么针对这样的成功调用都需要调用WSAClean,它会去递减winsock内部的计数器,如果为0,清理资源。所以如果没有匹配调用WSAStartup和WSAClean的话会造成资源泄漏。

经过上面的整理,一个大概的流程应该是下面这样:

 1 bool DoSomeThing()  
2 {
3 WORD version = MAKEWORD( 2, 2 );
4 WSADATA data;
5
6 int res = WSAStartup(version, &data);
7 if (res != 0)
8 {
9 return false;
10 }
11 else
12 {
13 if (LOBYTE(data.wVersion) != 2 ||
14 HIBYTE(data.wVersion) != 2 )
15 {
16 WSACleanup( );
17 return false;
18 }
19 }
20
21 //处理代码
22 ........
23
24 WSACleanup( );
25
26 return true;
27 }

注意问题来了,也许你已经觉得你已经很完整的进行了初始化和清理,而且判断的非常详细。那么当在这一堆“........”处理代码中出现什么异常或者错误导致函数提前退出的话,那么清理就永远也得不到调用,资源得不到释放。


好吧,在C++中找找出路。
在C++中,资源一般都会放在资源管理类中。它所依赖的条件就是C++类的构造函数和析构函数,不管程序因为异常或者是错误退出都会自动的被调用,那么关于资源的初始化和清理工作也都可以保证会调用。这样做会有个小小的问题,就是你不能直接的控制初始化。需要通过类的接口间接的得到初始化的信息,但是同封装初始化和清理来说,显然利大于弊。

.h

 1 /**@file        sock_init.h 
2 *@author $Author$
3 *@version $Recv$
4 *@date $Date$
5 */
6 #ifndef SOCK_INIT_H_
7 #define SOCK_INIT_H_
8
9 //< 防止windows和winsock头文件冲突
10 #ifndef WIN32_LEAN_AND_MEAN
11 #define WIN32_LEAN_AND_MEAN
12 #endif
13
14 #include <Windows.h>
15 #include <WinSock2.h>
16 #pragma comment(lib, "ws2_32")
17
18 /**@class SockInit
19 *@brief 初始化和清理winsock库
20 *@author $Author$
21 */
22 class SockInit
23 {
24 public:
25 /**@brief 初始化
26 *@param[in] version 加载的版本
27 */
28 SockInit(WORD version);
29 /**@brief 初始化
30 *@param[in] major 主版本
31 *@param[in] minor 副版本
32 */
33 SockInit(BYTE major, BYTE minor);
34 /**@brief 清理 */
35 ~SockInit();
36 public:
37 /**@brief 返回是否加载成功 */
38 bool IsLoaded() const;
39 /**@brief 返回使用的版本 */
40 WORD UseVersion() const;
41 private:
42 /**@brief 初始化
43 *@param[in] version 加载的版本
44 */
45 void Init(WORD version);
46 private:
47 bool is_loaded; //< 是否成功加载了库
48 WORD use_version; //< 使用的版本
49 };
50
51 inline bool SockInit::IsLoaded() const
52 {
53 return is_loaded;
54 }
55
56 inline WORD SockInit::UseVersion() const
57 {
58 return use_version;
59 }
60
61 #endif

.cpp

 1 /**@file        sock_init.cpp 
2 *@author $Author$
3 *@version $Recv$
4 *@date $Date$
5 */
6
7 #include "sock_init.h"
8
9 SockInit::SockInit(WORD version)
10 {
11 Init(version);
12 }
13
14 SockInit::SockInit(BYTE major, BYTE minor)
15 {
16 Init(MAKEWORD(minor, major));
17 }
18
19 SockInit::~SockInit()
20 {
21 if (is_loaded)
22 {
23 WSACleanup();
24 }
25 }
26
27 void SockInit::Init(WORD version)
28 {
29 is_loaded = false;
30
31 WSADATA data;
32 int res = WSAStartup(version, &data);
33 if (res == 0)
34 {
35 is_loaded = true;
36 use_version = data.wVersion;
37 //log.WriteLog(LOG_INFO, "WSAStartup success.");
38 }
39 else
40 {
41 //log.WriteLog(LOG_ERROR, "WSAStartup failed. error = %d.", res);
42 }
43 }


作者: 木 头 发表于 2011-08-26 22:17 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"