学习socket最好能有两台以上联网的电脑,以及能获得公网IP的网络接入方式。接下来的教程我会兼顾winsock的代码,这主要是因为winsock本身对socket几乎是兼容的。所以,这里有必要先说明在VC环境中使用socket的一些简单设置,以及与Linux环境下的细微差别。

       本文使用的VC环境是2008 Express。

       我们在VC中建立一个控制台的空项目:

  TCP/UDP网络编程入门教程之九:win32下使用socket——WinSock

 TCP/UDP网络编程入门教程之九:win32下使用socket——WinSock

 TCP/UDP网络编程入门教程之九:win32下使用socket——WinSock

       我们着手构建自己的第一个winsock程序。

       首先win32下与Linux下的socket API需要包含不同的头文件。

       在Linux下是这些:

C++代码
  1. #include <unistd.h>  
  2. #include <sys/socket.h>  
  3. #include <arpa/inet.h>  

       win32下的winsock有多个版本,我所找到的资料中,老的版本是:

C++代码
  1. #include <winsock.h>  

       与之对应的需要的链接库为:

  TCP/UDP网络编程入门教程之九:win32下使用socket——WinSock

 TCP/UDP网络编程入门教程之九:win32下使用socket——WinSock

       这可能可以兼容非常古老的版本中的winsock,比如win98,而微软官方所推荐的是:

C++代码
  1. #include <winsock2.h>  

       链接库是:ws2_32.lib,这样就可以使用高版本的winsock。

       那么,什么是winsock的版本?这就涉及到winsock的初始化函数WSAStartup:

       http://msdn.microsoft.com/en-us/library/ms742213(v=VS.85).aspx

       上面是微软的官方说明,我这里构建一个简单的类,希望每次使用的时候引入一个类对象就可以了。

C++代码
  1. class WinsockAPI{  
  2. private:  
  3.     WSADATA wsaData;  
  4. public:  
  5.     WinsockAPI(int low_byte = 2, int high_byte = 2);  
  6.     ~WinsockAPI();  
  7.     void showVersion() const;  
  8. };  

       WSADATA是记录着winsock信息的结构。

C++代码
  1. //class WinsockAPI  
  2.   
  3. WinsockAPI::WinsockAPI(int low_byte, int high_byte)  
  4. {  
  5.     const WORD wVersionRequested = MAKEWORD(low_byte, high_byte);  
  6.     int wsa_startup_err = WSAStartup(wVersionRequested, &wsaData);  
  7.     if (wsa_startup_err != 0) {  
  8.         std::cerr << "WSAStartup() failed." << std::endl;  
  9.         throw wsa_startup_err;  
  10.     }  
  11. }  
  12.   
  13. WinsockAPI::~WinsockAPI()  
  14. {  
  15.     WSACleanup();  
  16. }  
  17.   
  18. void WinsockAPI::showVersion() const  
  19. {  
  20.     std::cout    << "The version of Winsock.dll is "   
  21.                 << int(LOBYTE(wsaData.wVersion))   
  22.                 << "."   
  23.                 << int(HIBYTE(wsaData.wVersion))   
  24.                 << "."   
  25.                 << std::endl;  
  26.     return;  
  27. }  

       首先,宏MAKEWORD()将两个int转换为winsock形式的版本号,我这里默认是是2.2,就只需要MAKEWORD(2, 2),如果是老版本的,最低应该是1.0。WSAStartup()将winsock的初始化信息写入一个WSADATA结构(我们这里的wsaData),如果成功返回0,失败将返回一个int的错误代码。这个错误代码直接表示了错误信息,微软官方建议不使用winsock的通用异常信息获取函数WSAGetLastError()获取WSAStartup()的错误信息,这可能是因为如果WSAStartup()失败,那么winsock的错误信息不一定能够正确的构建出来的缘故。

       最后,winsock结束后用WSACleanup()清理。

       因为socket本身的复杂性,异常信息提示非常重要。WSAGetLastError()的官方说明如下:

       http://msdn.microsoft.com/en-us/library/ms741580(VS.85).aspx

       错误代码所反馈的信息查询在这里:

       http://msdn.microsoft.com/en-us/library/ms740668(v=VS.85).aspx

       最后,需要注意的问题是,因为socket是构建在UNIX系统下的(BSD socket是当今所有socket的基础),所以socket很好的利用了UNIX体系“一切都是文件”的性质,每个socket本身也就是一个UNIX文件描述符,因此,Linux下的socket是用关闭文件的函数close()关闭的。但是win32下没这个性质,所以winsock是另外一种抽象,但是好在同样用int作为描述符,关闭需要专门为winsock定做的函数closesocket()。

       下篇文章重写了TCP Server的代码(类的抽象和构造也重新写了,将在下一章解释),作为winsock使用的演示。

除非特别注明,鸡啄米文章均为原创
转载请标明本文地址:http://www.jizhuomi.com/software/418.html
2015年8月11日
作者:鸡啄米 分类:软件开发 浏览: 评论:0