Qt是一个跨平台的GUI开发语言,它是对C++在图形设计方面上的一种扩充。Qt本身包含一系列用来设计图形界面的类,并且对C++原有的类都进行了再次封装。如果你的程序采用Qt的类库,那么源程序在不同平台重新编译即可;如果程序中使用某些C++或C库函数,那么在移植时就需要针对不同平台作一些改动。
本文所举例的移植代码是基于socket API的C/S模型的客户端,该客户端的原始代码在linux系统下完成(以下称为“源代码”),现在要将其移植到windows平台下(以下称“移植代码”)。源代码的界面部分采用Qt完成,而通信部分则是采用原始的socket接口。
1.加入动态库
在linux系统中,socket API属于libc库,因此只需在程序中加头文件即可。而在windows系统下,由于socket接口是继承Unix系统而来,因此需要加入wsock32库,并且加上相应的头文件winsock2.h。加入该库具体的做法是在工程问价中加入下面的语句:
LIBS += -lwsock32
2.初始化套接字库
在windows下有两套socket API,一种是经过C++封装的csocket类,而另一种则是原始的socket接口,为了降低移植的复杂性,我们采用后者。
在将wsock32动态库加入移植程序后,socket接口还不能使用,因为在这之前必须使用WSAStartup函数对该库进行初始化。具体的初始化代码可以参考如下:
WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(1,1); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { return; } if ( LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1 ) { WSACleanup(); return;
WSAStartup函数有两个参数,wVersionRequested用来向该函数传递socket接口调用者可以使用socket的最高版本号,通过MAKEWORD宏即可完成版本号的组装,该变量的低字节指定主版本号而低字节指定次版本号。wsaData用来接收socket函数执行期间的一些数据。
当WSAStartup函数初始化动态库成功时返回0,否则返回-1。
当初始化成功后,还要再确认已加载的动态库的版本是否和我们所指定的动态库版本相吻合,如果不符合,则通过WSACleanup函数清除已加载的动态库。
动态库加载成功后,接下来就可以使用socket接口函数了,当使用完毕时,需要用WSACleanup函数卸载动态库。
3.更改套接字描述符
在使用一系列socket接口之前,必须使用socket函数创建套接字。在linux下,原始的socket函数返回的套接字描述符是整型,但是在windows下,该函数返回的套接字描述符是SOCKET类型。因此源代码和移植代码参考如下:
源代码:
int sockfd; if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { ui->statusLabel->setText("ERROR:socket connceting fail!"); exit(1); }
移植代码:
SOCKET sockfd; if ((cli.sockfd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { ui->statusLabel->setText("ERROR:socket connceting fail!"); exit(1); }
既然在移植代码中套接字描述符不是整型,那么其错误返回值也应该不是-1而是标准的错误返回值INVALID_SOCKET。
4.close函数
源代码中关闭套接字选用close(),而移植程序相应的使用closesocket()。并且此时用WSACleanup()关闭已加载的动态库。
进过上述几个部分的修改,此时移植程序在windows下即可编译成功。