软件时常需要更新,如果通过在线通知用户肯定会更方便,实现原理也很简单,通过获取服务器文件中版本号与软件自身版本号对比,给出提示。下面把实现的代码(C++)贴出来,供大家参考。
0.用到的头文件
1
2
|
#include
#pragma comment(lib, "WS2_32") // 链接到WS2_32.lib
|
1.启动Windows Sockets,初始化WS2_32.dll
1
2
3
4
5
6
7
|
WSADATA wsaData;
WORD
sockVersion = MAKEWORD(2, 2);
if
(::WSAStartup(sockVersion, &wsaData) != 0)
{
::WSACleanup();
return
FALSE;
}
|
2. 通过"套接字"向网络发出请求或者应答网络请求.
1
2
3
4
5
6
7
|
SOCKET sClient;
int
ret;
sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if
(sClient == INVALID_SOCKET)
{
return
FALSE;
}
|
3.设置发送和接收时间为超时8秒
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// set Recv and Send time out
int
TimeOut = 8000;
// 设置发送超时8秒
if
(setsockopt(sClient, SOL_SOCKET, SO_SNDTIMEO, (
char
*)&TimeOut,
sizeof
(TimeOut)) == SOCKET_ERROR)
{
closesocket(sClient);
return
FALSE;
}
if
(setsockopt(sClient, SOL_SOCKET, SO_RCVTIMEO, (
char
*)&TimeOut,
sizeof
(TimeOut)) == SOCKET_ERROR)
{
closesocket(sClient);
return
FALSE;
}
|
4.获取与套接口相关的操作参数
1
2
3
4
5
6
7
|
unsigned
long
ul = 1;
ret = ioctlsocket(sClient, FIONBIO, (unsigned
long
*)&ul);
if
(ret == SOCKET_ERROR)
{
closesocket(sClient);
return
FALSE;
}
|
5.sockaddr结构初始化,可通过设置服务器ip或网站地址。
gethostbyname()返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针。结构的声明与gethostaddr()中一致。
inet_addr(const char* strptr)返回:若字符串有效则将字符串转换为32位二进制网络字节序的IPV4地址,否则为INADDR_NONE
1
2
3
4
5
6
7
8
9
10
11
12
|
struct
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(80);
struct
hostent *pURL = gethostbyname(
"www.yanxin8.com"
);
//const char* ip = "115.28.9.132";
//server.sin_addr.s_addr = inet_addr(ip);
server.sin_addr.s_addr = *((unsigned
long
*)pURL->h_addr);
if
(server.sin_addr.s_addr == INADDR_NONE)
{
closesocket(sClient);
return
FALSE;
}
|
6.与远程主机建立连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
BOOL
bConnRe = FALSE;
if
(connect(sClient, (
struct
sockaddr *)&server,
sizeof
(server)) == -1)
{
struct
timeval timeout_val;
fd_set set;
FD_ZERO(&set);
FD_SET(sClient, &set);
timeout_val.tv_sec = 1;
timeout_val.tv_usec = 0;
if
(select(0, NULL, &set, NULL, &timeout_val) > 0)
{
bConnRe = TRUE;
}
else
bConnRe = FALSE;
}
else
bConnRe = TRUE;
if
(!bConnRe)
{
closesocket(sClient);
return
FALSE;
}
|
7.等待接收时间协议返回的时间。学习了Winsock I/O模型之后,最好使用异步I/O,以便设置超时。
按照http协议,发送请求数据
char *request = "GET /version.txt HTTP/1.0\r\nHost:www.xxx.com\r\nConnection: Close\r\n\r\n";
GET这个是表示以什么方式请求,HTTP中还有很多其他的请求方式,常用的GET POST
version.txt,要获取的资源的名称,version.txt为网站服务器根目录下的文件
HTTP/1.0表示http协议的版本
Host:www.xxx.com,用来指定访问的主机。
1
2
3
4
5
|
int
nRecv = 0;
///version.txt
char
*request =
"GET /version.txt HTTP/1.0\r\nHost:www.xxx.com\r\nConnection: Close\r\n\r\n"
;
ret = send(sClient, request,
strlen
(request), 0);
Sleep(300);
|
8.接收返回的数据,然后做解析。下面是返回的数据,可以看到最后一行为设定的软件版本。
1
2
3
4
5
6
7
8
9
10
|
HTTP/1.1 200 OK
Date: Wed, 29 Apr 2015 08:08:02 GMT
Server: Apache/2.4.10 (Unix) OpenSSL/1.0.1e-fips mod_fastcgi/2.4.6
Last-Modified: Tue, 28 Apr 2015 11:04:41 GMT
ETag: "10-514c6d4462440"
Accept-Ranges: bytes
Content-Length: 16
Connection: close
Content-Type: text/plain
noteCard=V1.0.2;
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
char
buf[2000] = { 0 };
nRecv = ::recv(sClient, buf, 2000, 0);
if
(nRecv > 0){
string str(buf);
//strstr(buf, "noteCard=");
int
pos1 = str.find(
"noteCard="
);
if
(pos1 != -1){
pos1 += 9;
int
pos2 = str.find(
";"
, pos1);
verstr = str.substr(pos1, pos2 - pos1);
return
true
;
}
}
|
9.关闭socket
1
2
3
|
closesocket(sClient);
::WSACleanup();
return
FALSE;
|