第23章 尝试互联网(4)【全书完】

23.4 WinInet和FTP

(1)WinInet接口(含HTTP、FTP)及FTP函数层次关系

(2)Ftp函数介绍

  ①InternetOpen——初始化,它告诉 Internet DLL 初始化内部数据结构并准备接收应用程序之后的其他调用。


参数


含义


LPCTSTR lpszAgent


调用WinInet函数的应用程序名字,在HTTP协议中作为用户代理项


DWORD   dwAccessType


访问要求类型:

INTERNET_OPEN_TYPE_DIRECT:解析所有本地主机,使用直接连接网络。

INTERNET_OPEN_TYPE_PRECONFIG:获取代理或直接从注册表中的配置,使用代理连接网络。

INTERNET_OPEN_TYEP_PRECONFIG_WITH_NO_AUTOPROXY:返回注册表中代理或直接配置,并防止Microsoft Jscript或INS文件的使用

INTERNET_OPEN_TYPE_PROXY:为代理传递请求


LPCTSTR lpszProxyName


当dwAccessType指定为INTERNET_OPEN_TYPE_PROXY时,为代理服务器名字。


LPCTSTR lpszProxyBypass


指定一个字符串,它提定一个可选的主机名列表或IP地址


DWORD   dwFlags


INTERNET_FLAG_ASYNC:仅作用于在该函数返回句柄的子句柄上的异步请求

INTERNET_FLAG_FROM_CACHE:不做网络请求,所以的实体由缓存给出,如果请求的条目不在缓存中,会返回ERROR_FILE_NOT_FOUND错误。

INTERNET_FLAG_OFFLINE:与INTERNET_FLAG_FROM_CACHE一样。

    举例:hIntSession = InternetOpen(szAppName,INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,INTERNET_FLAG_ASYNC);

  ②InternetConnect——建立 Internet 的连接,返回连接句柄


参数


含义


HINTERNET hInternet


InternetOpen返回的句柄


LPCTSTR       lpszServerName


连接的IP或者主机名


INTERNET_PORT nServerPort


连接的端口。如0,则为默认端口


LPCTSTR       lpszUsername


用户名,如无置NULL


LPCTSTR       lpszPassword


密码,如无置NULL


DWORD         dwService


使用的服务类型,可以使用以下

INTERNET_SERVICE_FTP(1):连接到一个FTP服务器

INTERNET_SERVICE_GOPHER(2):Gopher服务器

INTERNET_SERVICE_HTTP(3):连接到一个 HTTP 服务器上


DWORD         dwFlags


文档传输形式及缓存标记。一般置0。


DWORD_PTR     dwContext


当使用回叫信号时, 用来识别应用程序的前后关系


返回值:非0——成功;0——失败,要用InternetCloseHandle来关闭这个句柄

  ③FtpFindFirstFile——是用来设置ftp当前目录的


参数


含义


HINTERNET hConnect


InternetConnect返回的FTP会话句柄


LPCTSTR lpszSearchFile


在FTP服务器上特定的目录里,要查询的指定名称的目录或文件名的文件,还可以使用通配符查找(如*、?)


LPWIN32_FIND_DATA lpFindFileData


就是用来保存查找后,所返回的文件的信息


DWORD         dwFlags


文档传输形式及缓存标记。一般置0。


DWORD_PTR     dwContext


当使用回叫信号时, 用来识别应用程序的前后关系。 一般为0


返回值:有效句柄表示成功。NULL表示失败,可用GetLastError返回错误代码。

  ④InternetFindNextFile——查找下一个文件或目录


参数


含义


HINTERNET hConnect


hFind 是 FtpFindFirstFile 调用所返回的句柄


LPWIN32_FIND_DATA lpFindFileData


用来保存查找后,所返回的文件的信息


返回值:如果调用成功, 返回 True,否则为False,可进一步调用GetLastError查询错误代码,如果为 ERROR_NO_MORE_FILES表明再没有文件存在了。边查找,边可以从lpFindFileData提取文件名/目录名。

  ⑤FtpGetFile——下载文件到本地磁盘


参数


含义


HINTERNET hConnect


InternetConnect返回的FTP会话句柄


LPCTSTR lpszRemoteFile


FTP服务器上的文件名


LPCTSTR lpszNewFile


本地机上创建的文件


BOOL fFailIfExists


0——替换本地文件

1——如果本地文件已经存在则取消


DWORD dwFlagsAndAttributes


用来指定本地文件的文件属性(详细参考CreateFile函数)

FILE_ATTRIBUTE_NORMAL、FILE_ATTRIBUTE_HIDDEN、

FILE_ATTRIBUTE_READONLY、FILE_ATTRIBUTE_ARCHIVE等


DWORD dwFlags


FTP_TRANSFER_TYPE_ASCII(1):用ASCII传输文件

FTP_TRANSFER_TYPE_BINARY(2):是用二进制传输文件


DWORD dwContext


当使用回叫信号时, 用来识别应用程序的前后关系。 一般为0


返回值:有效句柄表示成功。NULL表示失败,可用GetLastError返回错误代码。

【UpdDemo程序】——读取FTP服务器上的文件

效果图
                                           服务器上的目录结构                                                                      正在从FTP下载文件

                                             

软件运行时截图

/*------------------------------------------------------------
   UPDDEMO.C --   Demonstrates Anonymous FTP Access
                    (c) Charles Petzold, 1998
  ------------------------------------------------------------*/

#include <windows.h>
#include <process.h>
#include <wininet.h>
#include "resource.h"

#pragma  comment(lib,"WININET.LIB")

//用户自定义消息
#define WM_USER_CHECKFILE (WM_USER + 1)
#define WM_USER_GETFILES  (WM_USER + 2)

//FTP下载的信息
#define FTPSERVER    TEXT("ftp.5iedu.net")
#define USERNAME     TEXT("rollingstone")
#define PASSWORD     TEXT("approach304304")
#define DIRECTORY     TEXT("/rollingstone/web")
#define TEMPLATE TEXT("UD??????.TXT")  //指定文件名格式的模版(其中的?为通配符,eg.UD201507.TXT)

//用来存储文件名和内容的结构体
typedef struct
{
    TCHAR* szFileName;
    char*  szContents;
}FILEINFO,*PFILEINFO;

typedef struct
{
    int iNum;
    FILEINFO info[1];
}FILELIST,*PFILELIST;

typedef struct   //供子线程使用的结构体
{
    BOOL bContinue;
    HWND hwnd;
}PARAMS,*PPARAMS;

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
BOOL    CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
VOID    FtpThread(PVOID);

//程序所用到的其他函数的声明
FILELIST* GetFileList(VOID);
int    Compare(const FILEINFO *, const FILEINFO *);
VOID   ButtonSwitch(HWND, HWND, TCHAR*);

TCHAR szAppName[] = TEXT("UpdDemo");
HINSTANCE  hInst;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;

     hInst = hInstance;

     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     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,                  // window class name
                          TEXT ("Update Demo with Anonymous FTP"), // window caption
                          WS_OVERLAPPEDWINDOW | WS_VSCROLL,        // window style
                          CW_USEDEFAULT,              // initial x position
                          CW_USEDEFAULT,              // initial y position
                          CW_USEDEFAULT,              // initial x size
                          CW_USEDEFAULT,              // initial y size
                          NULL,                       // parent window handle
                          NULL,                       // window menu handle
                          hInstance,                  // program instance handle
                          NULL) ;                     // creation parameters

     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;

     //主窗口显示后,检查是否存在最新的文件
     SendMessage(hwnd, WM_USER_CHECKFILE, 0, 0);

     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static int cxClient, cyClient, cxChar, cyChar;
    static FILELIST* pList;
    SCROLLINFO    si;
    HDC         hdc;
    PAINTSTRUCT ps;
    SYSTEMTIME  st;
    TCHAR   szFileName[MAX_PATH];
    int     i;

    switch (message)
    {
    case WM_CREATE:
        cxChar = LOWORD(GetDialogBaseUnits());
        cyChar = HIWORD(GetDialogBaseUnits());
        return 0;

    case WM_SIZE:
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);
        si.cbSize = sizeof(SCROLLINFO);
        si.fMask = SIF_RANGE | SIF_PAGE;
        si.nMin = 0;
        si.nMax = pList ? pList->iNum - 1 : 0;
        si.nPage = cyClient / cyChar;
        SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
        return 0;

    case WM_VSCROLL:
        si.cbSize = sizeof(SCROLLBARINFO);
        si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
        GetScrollInfo(hwnd, SB_VERT, &si);

        switch (LOWORD(wParam))
        {
        case SB_LINEDOWN:  si.nPos += 1; break;
        case SB_LINEUP:    si.nPos -= 1; break;
        case SB_PAGEDOWN:  si.nPos += si.nPage; break;
        case SB_PAGEUP:    si.nPos -= si.nPage; break;
        case SB_THUMBPOSITION: si.nPos = HIWORD(wParam); break;
        default:
            return 0;
        }
        si.fMask = SIF_POS;
        SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
        InvalidateRect(hwnd, NULL, TRUE);
        return 0;

    case WM_USER_CHECKFILE:
        //获得系统日期、文件名(年和月格式)
        GetSystemTime(&st);
        wsprintf(szFileName, TEXT("UD%04i%2i.TXT"), st.wYear, st.wMonth);

        //检查一下文件是否存在,如果存在,则读取所有文件
        if (GetFileAttributes(szFileName) !=(DWORD)-1)
        {
            SendMessage(hwnd, WM_USER_GETFILES, 0, 0);
            return 0;
        }

        //如果文件不存在,则从Internet中获取
        //但首先要检测磁盘的类型,当参数为NULL时,表示当前目录的驱动器类型
        //如果程序当前的目录是在光驱上的,则退出(因为后面要拷贝文件到程序
        //所在目录下。
        if (DRIVE_CDROM == GetDriveType(NULL))
        {
            MessageBox(hwnd, TEXT("Cannot run this program from CD-ROM!"),
                szAppName, MB_OK | MB_ICONEXCLAMATION);
            return 0;
        }

        //询问用户是否要连接到网络
        if (IDYES == MessageBox(hwnd,
                                TEXT("Update information from Internet?"),
                                szAppName,
                                MB_YESNO | MB_ICONQUESTION))
                DialogBox(hInst, szAppName, hwnd, DlgProc);

        //更新显示
        SendMessage(hwnd, WM_USER_GETFILES, 0, 0);
        return 0;

    case WM_USER_GETFILES:
        SetCursor(LoadCursor(NULL, IDC_WAIT));
        ShowCursor(TRUE);

        //从磁盘文件中读取所有的文件列表
        pList = GetFileList();
        ShowCursor(FALSE);
        SetCursor(LoadCursor(NULL, IDC_ARROW));

        //模拟发送一个WM_SIZE消息来改变滚动条和重绘(因为滚动条的大小与文件数量有关)
        SendMessage(hwnd, WM_SIZE, 0, MAKELONG(cxClient, cyClient));
        InvalidateRect(hwnd, NULL, TRUE);
        return 0;

    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);

        //TA_UPDATECP:每次文字输出调用后当前基准点改变。当前位置作为基准点
        SetTextAlign(hdc, TA_UPDATECP);

        si.cbSize = sizeof(SCROLLINFO);
        si.fMask = SIF_POS;
        GetScrollInfo(hwnd, SB_VERT, &si);

        if (pList)
        {
            for (i = 0; i < pList->iNum;i++)
            {
                MoveToEx(hdc, cxChar, (i - si.nPos)*cyChar, NULL);
                TextOut(hdc, 0, 0, pList->info[i].szFileName, lstrlen(pList->info[i].szFileName));
                TextOut(hdc, 0, 0, TEXT(":"), lstrlen(TEXT(":")));
                TextOutA(hdc, 0, 0, pList->info[i].szContents, strlen(pList->info[i].szContents));
            }
        }

        EndPaint(hwnd, &ps);
        return 0;

    case WM_DESTROY:
        if (pList)
        {
            //for (i = 0; i < pList->iNum; i++)
            //{
            //    if (pList->info[i].szFileName)
            //        free(pList->info[i].szFileName);
            //    if (pList->info[i].szContents)
            //        free(pList->info[i].szContents);
            //}

            //free(pList->info);
        }
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

BOOL    CALLBACK DlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static PARAMS params;
    switch (message)
    {
    case WM_INITDIALOG:
        params.bContinue = TRUE;
        params.hwnd = hwnd;
        _beginthread(FtpThread, 0, &params);
        return TRUE;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDCANCEL:
            params.bContinue = FALSE;
            return TRUE;

        case IDOK:
            EndDialog(hwnd, 0);
            return TRUE;
        }
        return FALSE;

    case WM_CLOSE:
        EndDialog(hwnd, FALSE);
        return TRUE;
    }
    return FALSE;
}

//FtpThread:从FTP服务器读取文本,并拷贝到本地磁盘中
VOID    FtpThread(PVOID parg)
{
    BOOL bSuccess;
    PPARAMS pparams;
    HWND hwndStatus, hwndButton;
    HINTERNET hIntSession, hFtpSession, hFind;
    TCHAR  szBuffer[64];
    WIN32_FIND_DATA  finddata;

    pparams = (PARAMS*)parg;
    hwndStatus = GetDlgItem(pparams->hwnd, IDC_STATUS);
    hwndButton = GetDlgItem(pparams->hwnd, IDCANCEL);

    //打开Internet会话
    hIntSession = InternetOpen(szAppName, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL,
                                  INTERNET_FLAG_PASSIVE); //INTERNET_FLAG_ASYNC,本例用异步会不成功
    if (NULL == hIntSession)
    {
        wsprintf(szBuffer, TEXT("InternetOpen error %i"), GetLastError());
        ButtonSwitch(hwndStatus, hwndButton, szBuffer);
        _endthread();
    }

    SetWindowText(hwndStatus, TEXT("Internet session opened..."));

    //检查用户是否按了取消按钮
    if (!pparams->bContinue)
    {
        InternetCloseHandle(hIntSession);
        ButtonSwitch(hwndStatus, hwndButton, NULL);
        _endthread();
    }

    //打开FTP会话
    hFtpSession = InternetConnect(hIntSession, FTPSERVER, INTERNET_DEFAULT_FTP_PORT, USERNAME,
                                         PASSWORD, INTERNET_SERVICE_FTP, 0, 0);
    if (NULL == hFtpSession)
    {
        wsprintf(szBuffer, TEXT("InternetConnect error %i"), GetLastError());
        ButtonSwitch(hwndStatus, hwndButton, szBuffer);
        InternetCloseHandle(hIntSession);
        _endthread();
    }
    SetWindowText(hwndStatus, TEXT("Ftp session opened..."));

    //检查用户是否按了取消按钮
    if (!pparams->bContinue)
    {
        InternetCloseHandle(hFtpSession);
        InternetCloseHandle(hIntSession);
        ButtonSwitch(hwndStatus, hwndButton, NULL);
        _endthread();
    }

    //设置FTP当前目录
    bSuccess = FtpSetCurrentDirectory(hFtpSession, DIRECTORY);
    if (!bSuccess)
    {
        wsprintf(szBuffer, TEXT("Cannot set directory to %s"),DIRECTORY);
        InternetCloseHandle(hFtpSession);
        InternetCloseHandle(hIntSession);
        ButtonSwitch(hwndStatus, hwndButton, szBuffer);
        _endthread();
    }

    SetWindowText(hwndStatus, TEXT("Directory found..."));

    //检查用户是否按了取消按钮
    if (!pparams->bContinue)
    {
        InternetCloseHandle(hFtpSession);
        InternetCloseHandle(hIntSession);
        ButtonSwitch(hwndStatus, hwndButton, NULL);
        _endthread();
    }

    //获取第1个匹配特征文件名的文件
    hFind = FtpFindFirstFile(hFtpSession, TEMPLATE, &finddata, 0, 0);
    if (NULL == hFind)
    {
        InternetCloseHandle(hFtpSession);
        InternetCloseHandle(hIntSession);
        ButtonSwitch(hwndStatus, hwndButton, TEXT("Cannot find files"));
        _endthread();
    }

    //将所有文件名符合“UD??????.TXT”的文件下载到本地磁盘的当前目录下
    do
    {
        //检查用户是否按了取消按钮
        if (!pparams->bContinue)
        {
            InternetCloseHandle(hFtpSession);
            InternetCloseHandle(hIntSession);
            ButtonSwitch(hwndStatus, hwndButton, NULL);
            _endthread();
        }

        wsprintf(szBuffer, TEXT("Reading file %s..."), finddata.cFileName);
        SetWindowText(hwndStatus, szBuffer);

        //将文件从Ftp服务器下载到本地磁盘,如果本地磁盘己经存在,则失败
        FtpGetFile(hFtpSession, finddata.cFileName, finddata.cFileName, TRUE,
                       FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_BINARY, 0);
    }
    while (InternetFindNextFile(hFind,&finddata));

    InternetCloseHandle(hFind);
    InternetCloseHandle(hFtpSession);
    InternetCloseHandle(hIntSession);
    ButtonSwitch(hwndStatus, hwndButton, TEXT("Internet Download Complete"));
}

//ButtonSwitch:用来显示最后的状态并将“取消”按钮改变为“OK”按钮
VOID  ButtonSwitch(HWND hwndStatus, HWND hwndButton, TCHAR* szText)
{
    if (szText)
        SetWindowText(hwndStatus, szText);
    else
        SetWindowText(hwndStatus, TEXT("Internet Session Cancelled"));

    SetWindowText(hwndButton, TEXT("OK"));
    SetWindowLong(hwndButton, GWL_ID, IDOK);
}

//从磁盘中读取文件并把各文件名和内容保存在指定的缓冲区中
FILELIST* GetFileList(VOID)
{
    DWORD dwRead;
    FILELIST* pList;
    int iNum,iSize;
    HANDLE  hFile, hFind;

    WIN32_FIND_DATA finddata;

    hFind = FindFirstFile(TEMPLATE, &finddata);
    if (hFind == INVALID_HANDLE_VALUE)
        return NULL;

    pList = NULL;
    iNum = 0;
    do
    {
        //打开文件并获得文件大小
        hFile = CreateFile(finddata.cFileName, GENERIC_READ, FILE_SHARE_READ,
                            NULL, OPEN_EXISTING, 0, NULL);
        if (hFile == INVALID_HANDLE_VALUE)
            continue;

        iSize = GetFileSize(hFile, NULL);
        if (iSize == (DWORD)-1)
        {
            CloseHandle(hFile);
            continue;
        }

        //重新分配FILELIST结构体,以增加一个新的项目
        pList = realloc(pList, sizeof(FILELIST)+iNum*sizeof(FILEINFO));
        //分配空间以存储文件名
        pList->info[iNum].szFileName = malloc(lstrlen(finddata.cFileName) + sizeof(TCHAR));
        lstrcpy(pList->info[iNum].szFileName, finddata.cFileName);
        //分配空间以存储文件的内容
        pList->info[iNum].szContents = malloc(iSize + 1);
        ReadFile(hFile, pList->info[iNum].szContents, iSize, &dwRead, NULL);
        pList->info[iNum].szContents[iSize] = 0;
        CloseHandle(hFile);
        iNum++;
    }
    while (FindNextFile(hFind,&finddata));

    //按文件名排序(降序)
    qsort(pList->info, iNum, sizeof (FILEINFO), Compare);
    pList->iNum = iNum;
    return pList;
}

int    Compare(const FILEINFO * pInfo1, const FILEINFO * pInfo2)
{
    return  lstrcmp(pInfo2->szFileName, pInfo1->szFileName);
}

//resource.h

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 UpdDemo.rc 使用
//
#define IDC_STATUS                      1001

// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        102
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1002
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

//UdpDemo.rc

// Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// 中文(简体,中国) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE
BEGIN
    "#include ""winres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE
BEGIN
    "\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED

/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

UPDDEMO DIALOGEX 0, 0, 211, 44
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Internet Download"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    PUSHBUTTON      "Cancel",IDCANCEL,83,26,50,14
    CTEXT           "",IDC_STATUS,15,11,178,8
END

/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
    "UPDDEMO", DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 204
        TOPMARGIN, 7
        BOTTOMMARGIN, 42
    END
END
#endif    // APSTUDIO_INVOKED

#endif    // 中文(简体,中国) resources
/////////////////////////////////////////////////////////////////////////////

#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//

/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED

23.5 其他网络常用函数

(1)和主机名相关的函数

  ①gethostbyname——将主机名转成IP


参数


含义


const char FAR *name


需要解析的主机名字符串


返回值——指向WinSock内部缓冲区一个HOSTENT结构体的指针。(因为一个主机名可能对应多个IP地址)

【图解HOSTENT结构体】

  ②gethostbyaddr函数——将IP地址转换成主机名


参数


含义


const char FAR *addr


指向IP地址的指针(注意,不是字符串,而是网络字节顺序的32位IP)


int len


IP地址的数据长度,当然是4个字节了


int type


地址的类型,一般为AF_INET


返回值


失败时返回0。

成功时返回HOSTENT结构体,其中的h_name指向转换后的主机名

  ③gethostname——获取本地计算机的主机名


参数


含义


const char FAR *addr


在指定的缓冲区返回本地计算机的主机名字符串


int namelen


指定缓冲区的大小

(2)获取套接字两端的地址信息

  ①getpeername——获取对端的IP地址和端口


参数


含义


SOCKET s


套接字句柄


struct sockaddr FAR *name


指向SOCKADDR_IN结构体的指针,函数会将对端的IP和端口信息


int FAR *namelen


指定缓冲区的长度


返回值


成功为0,失败SOCKET_ERROR。


注意:该函数不是获取对端IP和端口的唯一方法。如果连接是本机主动发起,那些连接时就己知这些信息。如果连接是对方发起,在accept函数时,也可以得到对方的地址信息。

  ②getsockname函数——获取本地端使用的IP地址和端口(特别是多网卡和系统自动选择端口时,可以通过该函数获知)。该函数也是将信息返回在sockaddr_in结构体中。

【其他网络函数测试程序】

#include <stdio.h>
#include "winsock2.h"

#pragma comment(lib,"ws2_32.lib")

//显示HOSTENT结构体的内容
void ShowHostEntInfo(HOSTENT* phe)
{
    char** ppIPList;
    char** ppAlias;

    SOCKADDR_IN sa;

    sa.sin_family = phe->h_addrtype;

    //只处理IP4
    if (phe->h_addrtype == AF_INET)
    {
        printf("正式主机名称:%s\n", phe->h_name);

        //主机可能有多个别名,分别打印出来
        for (ppAlias = phe->h_aliases; *ppAlias != NULL; ppAlias++) //ppAlias是个指针,所以++增量为4个字节
            printf("alias:%s\n", *ppAlias);

        //将IP地址打印出来
        for (ppIPList = phe->h_addr_list; *ppIPList != NULL; *ppIPList++)
        {
            sa.sin_addr.S_un.S_addr = (ULONG)(*(int*)*ppIPList); //取出来的IP,本身就是网络字节序的
            printf("address:%s\n", inet_ntoa(sa.sin_addr));
        }
    }
}

int main()
{
    WSADATA wsa;
    HOSTENT* phe;
    ULONG IP;
    char szBuffer[20];

    //char szHostName[] = "SantaClaus-PC";
    //char szHostName[] = "localhost";
    char szHostName[] = "www.baidu.com";

    WSAStartup(MAKEWORD(2, 0), &wsa);

    printf("将域名(www.baidu.com)或主机名转化为IP地址:\n");

    //通过gethostbyname将域名或主机名转化为IP地址
    phe = gethostbyname(szHostName);
    if (phe !=NULL)
        ShowHostEntInfo(phe);

    printf("\n将IP地址(127.0.0.1)转为主机名:\n");
    //通过gethostbyaddr将IP地址转为主机名
    IP =inet_addr("127.0.0.1");
    phe = gethostbyaddr((char*)&IP, 4, AF_INET);
    if (phe != NULL)
        ShowHostEntInfo(phe);

    //获取本机主机名
    gethostname(szBuffer, sizeof(szBuffer));
    printf("\n通过gethostname获取本机主机名:%s\n\n",szBuffer);

    WSACleanup();
    return 0;

}
时间: 2024-08-02 12:46:47

第23章 尝试互联网(4)【全书完】的相关文章

第23章 尝试互联网(3)

23.3.2 以非阻塞方式工作的TCP聊天室客户端 (1)WSAAsyncSelect函数——设置非阻塞模式 参数 含义 SOCKET s 套接字句柄 HWND hWnd 套接字的通知消息将被发往的hwnd的窗口过程 unsigned int wMsg 自定义通知消息的编号,如 #define WM_SOCKET WM_USER+XXX中任取一个. long lEvent 指定哪些通知码需要发送,可以是以下通知知的组合 ①FD_READ:套接字收到对端发送过来的数据,表明可以去读套接字了. ②F

第23章 尝试互联网(1)

23.1 Windows Socket接口简介 (1)TCP/IP模型 ①TCP/IP的核心协议运行于传输层和Internet层,主要包括TCP.UDP和IP协议,而TCP协议和UDP协议是以IP协议为基础而封装的.这两种协议提供了不同方式的数据通信服务. ②IP协议比喻为道路,则下一层的网络访问层上的协议相当于不同的铺路材料,上面的TCP和UPD协议相当于路上跑的不同类型的车辆,再上层应用层的协议相当于车上的丰富多彩的货物.他们都是以TCP.UDP为载体的. (2)WinSock动态库 ①早期

第23章 尝试互联网(2)

23.3 TCP应用程序设计 23.3.1 通信协议的工作线程的设计——阻塞模式 (1)设计TCP链路的通信协议 ①数据包的设计:数据包头和数据包体(可参考代码中的消息定义部分)——TLV(Type-Length-Value) 组成 说明 数据包头 包含命令代码字段和整个数据包大小的字段(这个字段长度是固定的),即使通信双方己约定好各种命令数据包的长度,可以直接从命令代码中间接地判断出该数据包的长度,但仍建议设计该结构头时,保留数据包长度这个字段. 命令代码如:登录命令.消息上传.下载命令.退出

Lua_第23章 C API 纵览

第23章 C  API 纵览 Lua是一个嵌入式的语言,意味着 Lua 不仅可以是一个独立运行的程序包也可以是一个用来嵌入其他应用的程序库.你可能觉得奇怪:如果 Lua 不只是独立的程序,为什么到目前为止贯穿整本书我们都是在使用 Lua 独立程序呢? 这个问题的答案在于 Lua 解释器(可执行的 lua).Lua解释器是一个使用 Lua 标准库实现的独立的解释器,它是一 个很小的应用(总共不超过500 行的代码).解释器负责程序和使用者的接口:从使用者那里获取文件或者字符串,并传给 Lua 标准

Spring Framework Reference Documentation 3.2.8.RELEASE 第23章中文翻译

23. JMS (Java Message Service) [中文翻译 by [email protected]] 23.1 介绍 Spring提供了一个JSM集成框架,简化了JMS API的使用.这点很像Spring对JDBC的集成. JMS大致提供生产消息和消费消息两类功能.JmsTemplate类用来生产消息和同步接收消息[译注:接收消息也就是消费消息].为了异步接收消息(异步接收消息类似于JavaEE的消息驱动Bean(Message-Driven Bean,MDB),Spring提供

4.26日第14次作业,23章项目整体绩效评估,24-32章信息安全相关知识

一.23章:项目整体绩效评估 1.三E审计是什么的合称?(记)P524 答:三E审计是经济审计.效率审计和效果审计的合称,因为三者的第一个英文字母均为E,顾称为三E审计. 2.霍尔三维结构是从哪三个方面考察系统工程的工作过程的?P527-528 答:霍尔三维结构是霍尔(A Hall)提出的关于系统方法论的结构,它从逻辑.时间.知识三方面考察系统工程的工作过程. 3.投资回收期的公式?(记,并理解)P533答:投资回收期的公式:(累计净现金流量出现正值的年份-1) + (上年累计净现金流量值的绝对

JavaScript高级程序设计(第三版)学习笔记20、21、23章

第20章,JSON JSON(JavaScript Object Notation,JavaScript对象表示法),是JavaScript的一个严格的子集. JSON可表示一下三种类型值: 简单值:字符串,数值,布尔值,null,不支持js特殊值:undefined 对象:一组无序的键值对 数组:一组有序的值的列表 不支持变量,函数或对象实例 注:JSON的字符串必须使用双引号,这是与JavaScript字符串最大的区别 对象 { "name":"Nicholas"

第23章 CSS边框图片效果

本章学习日后开发使用参考一下内容 https://www.qianduan.net/css3border-image-bian-kuang-tu-xiang-xiang-jie/ 或W3C 或者百度 未排版的PDF转WORD(不想排版了) 第 23章 CSS3边框图片效果学习要点:1.属性初探2.属性解释3.简写和版本 本章主要探讨 HTML5中 CSS3中边框图片背景的效果,通过这个新属性让边框更加的丰富多彩.一.属性解释CSS3提供了一个新的属性集合,用这几个属性可以嵌入图片形式的边框.这样

第23章、OnFocuChangeListener焦点事件(从零开始学Android)

在Android App应用中,OnFocuChangeListener焦点事件是必不可少的,我们在上一章的基础上来学习一下如何实现. 基本知识点:OnFocuChangeListener事件 一.界面 打开“res/layout/activity_main.xml”文件. 1.分别从工具栏向activity拖出2个编辑框EditText.控件来自Form Widgets. 2.打开activity_main.xml文件. [html] view plaincopy <LinearLayout