经典图书《windows程序设计(第5版)》第23章.doc_第1页
经典图书《windows程序设计(第5版)》第23章.doc_第2页
经典图书《windows程序设计(第5版)》第23章.doc_第3页
经典图书《windows程序设计(第5版)》第23章.doc_第4页
经典图书《windows程序设计(第5版)》第23章.doc_第5页
已阅读5页,还剩39页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

领略Internet涛儿软件工作室整理编译Internet全世界计算机透过不同协议交换信息的大型连结体近几年重新定义了个人计算的几个领域。虽然拨接信息服务和电子邮件系统在Internet流行开来之前就已经存在,但它们通常局限于文字模式,并且根本没有连结而是各自分隔的。例如,每一种信息服务都需要拨不同的电话号码,用不同的使用者ID和密码登录。每一种电子邮件系统仅允许在特定系统的缴款使用者之间发送和接收邮件。现在,往往只需要拨单一支电话就可以连结整个Internet,而且可以和有电子邮件地址的人进行全球通信。特别是在World Wide Web上,超文字、图形和多媒体(包括声音、音乐和视讯)的使用已经扩展了在线信息的范围和功能。如果要提供涵盖Windows中所有与Internet相关程序设计问题的彻底介绍,可能还需要再加上几本书才够。所以,本章实际上主要集中在如何让小型的Microsoft Windows应用程序能够有效地从Internet上取得信息的两个领域。这两个领域分别是Windows Sockets (Winsock) API和Windows Internet(WinInet)API支持的文件传输协议(FTP:File Transfer Protocol)的部分。Windows SocketsSocket是由University of California在Berkeley分校开发的概念,用于在UNIX操作系统上添加网络通讯支持。那里开发的API现在称为Berkeley socket interface。Sockets和TCP/IPSocket通常(但不专用于)与主宰Internet通信的传输控件协议/因特网协议(TCP/IP:Transmission Control Protocol/Internet Protocol)牵连在一起。因特网协定(IP:Internet Protocol),作为TCP/IP的组成部分之一,用来将数据打包成数据封包(datagram),该资料封包包含用于标识数据来源和目的地的表头信息。而传输控制协议(TCP:Transmission Control Protocol)则提供了可靠的传输和检查IP数据封包正确性的方法。在TCP/IP下,通讯端点由IP地址和端口号定义。IP地址包括4个字节,用于确定Internet上的服务器。IP地址通常按由点连结的四个小于255的数字的格式显示,例如31。埠号确定了特定的服务或服务器提供的服务。其中一些埠号已经标准化,以提供众所周知的服务。当Socket与TCP/IP合用时,Socket就是TCP/IP的通讯端点。因此,Socket指定了IP地址和端口号。网络时间服务下面给出的范例程序与提供时间协议(Time Protocol)的Internet服务器相连结。此程序将获得目前准确的日期和时间,并用此信息设定您的PC时钟。在美国,国家标准和技术协会(National Institute of Standards and Technology)(以前称为国家标准局(National Bureau of Standards)负责维护准确时间,该时间与世界各地的机构相联系。准确时间可用于无线电广播、电话号码、计算机拨号电话号码以及Internet,关于这些的所有文件都位于网站 /timefreq(网域名称bldrdoc指的是Boulder、Colorado、NIST Time的位置和Frequency Division)。我们只对NIST Network Time Service感兴趣,其详细的文件位于 /timefreq/service/nts.htm。此网页列出了十个提供NIST时间服务的服务器。例如,第一个名称为,其IP地址为30。(我曾经编写过一个使用非Internet NIST计算机拨接服务的程序,并发表于PC Magazine,您也可以在Ziff-Davis的网站 /pcmag/pctech/content/16/20/ut1620.001.html中找到。此程序对于想学习如何使用Windows Telephony API的人很有帮助。)在Internet上有三个不同的时间服务,每一个都由Request for Comment(RFC)描述为Internet标准。日期协议(Daytime Protocol)(RFC-867)提供了一个ASCII字符串用于指出准确的日期和时间。该ASCII字符串的准确格式并不标准,但人们可以理解其中的含义。时间协议(RFC-868)提供了一个32位的数字,用来表示从1900年1月1日至今的秒数。该时间是UTC(不考虑字母顺序,它表示世界时间坐标(Coordinated Universal Time),它类似于所谓的格林威治标准时间(Greenwich Mean Time)或者GMT英国格林威治时间。第三个协议称为网络时间协议(Network Time Protocol)(RFC-1305),该协议很复杂。对于我们的目的,即包括分析Socket和不断更新PC时钟,时间协议RFC-868已经够用了。RFC-868只是一个两页的简短文件,主要是说用TCP获得准确时间的程序应该有如下步骤:1. 连结到提供此服务的服务器埠37。 2. 接收32位的时间。 3. 关闭连结。现在我们已经知道了编写存取时间服务的Socket应用程序的每个细节。NETTIME程序Windows Sockets API,通常也称为WinSock,与Berkeley Sockets API兼容,因此,可以想象UNIX Socket程序代码可以顺利地拿到Windows上使用。Windows下更进一步的支持由对Berkeley Socket扩充的功能提供,其函数的形式是以WSA(WinSock API)为前缀。相关的概述和参考位于/Platform SDK/Networking and Distributed Services/Windows Sockets Version 2。NETTIME,如程序23-1所示,展示了使用WinSock API的方法。程序23-1 NETTIME NETTIME.C /*- NETTIME.C - Sets System Clock from Internet Services (c) Charles Petzold, 1998 -*/ #include #include resource.h #define WM_SOCKET_NOTIFY (WM_USER + 1) #define ID_TIMER 1 LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; BOOL CALLBACK MainDlg (HWND, UINT, WPARAM, LPARAM) ; BOOL CALLBACK ServerDlg (HWND, UINT, WPARAM, LPARAM) ; void ChangeSystemTime (HWND hwndEdit, ULONG ulTime) ; void FormatUpdatedTime (HWND hwndEdit, SYSTEMTIME * pstOld, SYSTEMTIME * pstNew) ; void EditPrintf (HWND hwndEdit, TCHAR * szFormat, .) ; HINSTANCE hInst ; HWND hwndModeless ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) static TCHAR szAppName = TEXT (NetTime) ; HWND hwnd ; MSG msg ; RECT rect ; WNDCLASS wndclass ; hInst = hInstance ; wndclass.style = 0 ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = NULL ; wndclass.hbrBackground = NULL ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass) MessageBox (NULL, TEXT (This program requires Windows NT!), szAppName, MB_ICONERROR) ; return 0 ; hwnd = CreateWindow (szAppName, TEXT (Set System Clock from Internet), WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; / Create the modeless dialog box to go on top of the window hwndModeless = CreateDialog (hInstance, szAppName, hwnd, MainDlg) ; / Size the main parent window to the size of the dialog box. / Show both windows. GetWindowRect (hwndModeless, &rect) ; AdjustWindowRect (&rect, WS_CAPTION | WS_BORDER, FALSE) ; SetWindowPos (hwnd, NULL, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE) ; ShowWindow (hwndModeless, SW_SHOW) ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; / Normal message loop when a modeless dialog box is used. while (GetMessage (&msg, NULL, 0, 0) if (hwndModeless = 0 | !IsDialogMessage (hwndModeless, &msg) TranslateMessage (&msg) ; DispatchMessage (&msg) ; return msg.wParam ; LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) switch (message) case WM_SETFOCUS: SetFocus (hwndModeless) ; return 0 ; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; return DefWindowProc (hwnd, message, wParam, lParam) ; BOOL CALLBACK MainDlg ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) static char szIPAddr32 = 30 ; static HWND hwndButton, hwndEdit ; static SOCKET sock ; static struct sockaddr_in sa ; static TCHAR szOKLabel32 ; int iError, iSize ; unsigned long ulTime ; WORD wEvent, wError ; WSADATA WSAData ; switch (message) case WM_INITDIALOG: hwndButton = GetDlgItem (hwnd, IDOK) ; hwndEdit = GetDlgItem (hwnd, IDC_TEXTOUT) ; return TRUE ; case WM_COMMAND: switch (LOWORD (wParam) case IDC_SERVER: DialogBoxParam (hInst, TEXT (Servers), hwnd, ServerDlg, (LPARAM) szIPAddr) ; return TRUE ; case IDOK: / Call WSAStartup and display description text if (iError = WSAStartup (MAKEWORD(2,0), &WSAData) EditPrintf (hwndEdit, TEXT (Startup error #%i.rn), iError) ; return TRUE ; EditPrintf (hwndEdit, TEXT (Started up %hsrn), WSAData.szDescription); / Call socket sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP) ; if (sock = INVALID_SOCKET) EditPrintf (hwndEdit, TEXT (Socket creation error #%i.rn), WSAGetLastError () ; WSACleanup () ; return TRUE ; EditPrintf (hwndEdit, TEXT (Socket %i created.rn), sock) ; / Call WSAAsyncSelect if (SOCKET_ERROR = WSAAsyncSelect (sock, hwnd, WM_SOCKET_NOTIFY, FD_CONNECT | FD_READ) EditPrintf ( hwndEdit, TEXT (WSAAsyncSelect error #%i.rn), WSAGetLastError () ; closesocket (sock) ; WSACleanup () ; return TRUE ; / Call connect with IP address and time-server port sa.sin_family = AF_INET ; sa.sin_port = htons (IPPORT_TIMESERVER) ; sa.sin_addr.S_un.S_addr = inet_addr (szIPAddr) ; connect(sock, (SOCKADDR *) &sa, sizeof (sa) ; / connect will return SOCKET_ERROR because even if it / succeeds, it will require blocking. The following only / reports unexpected errors. if (WSAEWOULDBLOCK != (iError = WSAGetLastError () EditPrintf (hwndEdit, TEXT (Connect error #%i.rn), iError) ; closesocket (sock) ; WSACleanup () ; return TRUE ; EditPrintf (hwndEdit, TEXT (Connecting to %hs.), szIPAddr) ; / The result of the connect call will be reported / through the WM_SOCKET_NOTIFY message. / Set timer and change the button to Cancel SetTimer (hwnd, ID_TIMER, 1000, NULL) ; GetWindowText (hwndButton, szOKLabel, sizeof (szOKLabel) /sizeof (TCHAR) ; SetWindowText (hwndButton, TEXT (Cancel) ; SetWindowLong (hwndButton, GWL_ID, IDCANCEL) ; return TRUE ; case IDCANCEL: closesocket (sock) ; sock = 0 ; WSACleanup () ; SetWindowText (hwndButton, szOKLabel) ; SetWindowLong (hwndButton, GWL_ID, IDOK) ; KillTimer (hwnd, ID_TIMER) ; EditPrintf (hwndEdit, TEXT (rnSocket closed.rn) ; return TRUE ; case IDC_CLOSE: if (sock) SendMessage (hwnd, WM_COMMAND, IDCANCEL, 0) ; DestroyWindow (GetParent (hwnd) ; return TRUE ; return FALSE ; case WM_TIMER: EditPrintf (hwndEdit, TEXT (.) ; return TRUE ; case WM_SOCKET_NOTIFY: wEvent = WSAGETSELECTEVENT (lParam) ; / ie, LOWORD wError = WSAGETSELECTERROR (lParam) ; / ie, HIWORD / Process two events specified in WSAAsyncSelect switch (wEvent) / This event occurs as a result of the connect call case FD_CONNECT: EditPrintf (hwndEdit, TEXT (rn) ; if (wError) EditPrintf (hwndEdit, TEXT (Connect error #%i.), wError) ; SendMessage (hwnd, WM_COMMAND, IDCANCEL, 0) ; return TRUE ; EditPrintf (hwndEdit, TEXT (Connected to %hs.rn), szIPAddr) ; / Try to receive data. The call will generate an error / of WSAEWOULDBLOCK and an event of FD_READ recv (sock, (char *) &ulTime, 4, MSG_PEEK) ; EditPrintf (hwndEdit, TEXT (Waiting to receive.) ; return TRUE ; / This even occurs when the recv call can be made case FD_READ: KillTimer (hwnd, ID_TIMER) ; EditPrintf (hwndEdit, TEXT (rn) ; if (wError) EditPrintf (hwndEdit, TEXT (FD_READ error #%i.), wError) ; SendMessage (hwnd, WM_COMMAND, IDCANCEL, 0) ; return TRUE ; / Get the time and swap the bytes iSize = recv (sock, (char *) &ulTime, 4, 0) ; ulTime = ntohl (ulTime) ; EditPrintf (hwndEdit, TEXT (Received current time of %u seconds ) TEXT (since Jan. 1 1900.rn), ulTime) ; / Change the system time ChangeSystemTime (hwndEdit, ulTime) ; SendMessage (hwnd, WM_COMMAND, IDCANCEL, 0) ; return TRUE ; return FALSE ; return FALSE ; B

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论