軟件時常需要更新,如果通過在線通知用戶肯定會更方便,實現原理也很簡單,通過獲取服務器文件中版本號與軟件自身版本號對比,給出提示。下面把實現的代碼(C++)貼出來,供大家參考。
0.用到的頭文件
1
2
|
#include <Shlwapi.h> #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;
|