// // GetHTTP3.cpp -- HTTPサーバーからファイルを取り寄せる // // このバージョンでは重複I/Oと // 完了関数を使用する // // ws2_32.libでコンパイル・リンクする // #include <fcntl.h> #include <io.h> #include <stdio.h> #include <winsock2.h> void GetHTTP(LPCSTR lpServerName, LPCSTR lpFileName); // // 重複I/O完了関数 // void CALLBACK RecvComplete(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags); // エラー表示用のヘルパーマクロ #define PRINTERROR(s) \ fprintf(stderr,"\n%s %d\n", s, WSAGetLastError()) #define BUFFER_SIZE 1024 // // 完了関数に追加情報を // 渡すための構造体 // typedef struct tagIOREQUEST { WSAOVERLAPPED over; // これは最初に記述しなければならない SOCKET Socket; BOOL fFinished; LPBYTE pBuffer; }IOREQUEST, *LPIOREQUEST; void main(int argc, char **argv) { WORD wVersionRequested = WINSOCK_VERSION; WSADATA wsaData; int nRet; // // 引数をチェックする // if (argc != 3) { fprintf(stderr, "\nSyntax: GetHTTP ServerName FullPathName\n"); return; } // // WinSock.dllを初期化する // nRet = WSAStartup(wVersionRequested, &wsaData); if (nRet) { fprintf(stderr, "\nWSAStartup() error (%d)\n", nRet); WSACleanup(); return; } // // WinSockのバージョンを調べる // if (wsaData.wVersion != wVersionRequested) { fprintf(stderr,"\nWinSock version not supported\n"); WSACleanup(); return; } // // バイナリファイル(.gif、.jpg、.exeなど)の // リダイレクションを機能させるために、 // stdoutをバイナリモードに設定する // _setmode(_fileno(stdout), _O_BINARY); // // GetHTTP()を呼び出してすべての処理を実行する // GetHTTP(argv[1], argv[2]); WSACleanup(); } void GetHTTP(LPCSTR lpServerName, LPCSTR lpFileName) { LPHOSTENT lpHostEntry; SOCKADDR_IN saServer; SOCKET Socket; int nRet; // // ホストアドレスの検索 // lpHostEntry = gethostbyname(lpServerName); if (lpHostEntry == NULL) { PRINTERROR("socket()"); return; } // TCP/IPストリームソケットを作成する Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (Socket == INVALID_SOCKET) { PRINTERROR("socket()"); return; } // // サーバーアドレス構造体の残りの部分を埋める // saServer.sin_family = AF_INET; saServer.sin_addr = *((LPIN_ADDR)*lpHostEntry->h_addr_list); saServer.sin_port = htons(80); // // ソケットを接続する // nRet = connect(Socket, (LPSOCKADDR)&saServer, sizeof(SOCKADDR_IN)); if (nRet == SOCKET_ERROR) { PRINTERROR("connect()"); closesocket(Socket); return; } // // HTTP要求を書式化して // 送信する // char szBuffer[1024]; sprintf(szBuffer, "GET %s\n", lpFileName); nRet = send(Socket, szBuffer, strlen(szBuffer), 0); if (nRet == SOCKET_ERROR) { PRINTERROR("send()"); closesocket(Socket); return; } // // 接続されたので、 // 受信バッファを指定することができる // // // ここではちょっとした工夫によって、 // 完了関数に追加情報を渡している。 // すべての追加情報をWSAOVERLAPPED構造体の // 最後に追加し、WSARecv()に // lpOverlappedパラメータとして渡す。 // 完了関数が呼び出されるときに、 // この追加情報を利用できる。 // BYTE aBuffer[BUFFER_SIZE]; IOREQUEST ioRequest; memset(&ioRequest.over, 0, sizeof(WSAOVERLAPPED)); ioRequest.Socket = Socket; ioRequest.fFinished = FALSE; ioRequest.pBuffer = aBuffer; WSABUF wsabuf; wsabuf.len = BUFFER_SIZE; wsabuf.buf = (char *)aBuffer; DWORD dwRecv; DWORD dwFlags = 0; nRet = WSARecv(Socket, &wsabuf, 1, &dwRecv, &dwFlags, (LPWSAOVERLAPPED)&ioRequest, RecvComplete); if (nRet == SOCKET_ERROR) { if (WSAGetLastError() != WSA_IO_PENDING) { PRINTERROR("WSARecv()"); closesocket(Socket); return; } } // ファイルの内容を受け取り、stdoutに書き出す while(1) { // // その他の処理をここで行う // // // SleepEx()を使って、 // 警告可能な待機状態にあることを通知する // SleepEx(0, TRUE); // // 完了関数によって完了が通知された場合 // if (ioRequest.fFinished) break; } closesocket(Socket); } void CALLBACK RecvComplete(DWORD dwError, DWORD cbRecv, LPWSAOVERLAPPED lpOver, DWORD dwFlags) { // // エラーをチェックする // if (dwError) { fprintf(stderr,"\nRecvComplete() error: %ld", dwError); return; } LPIOREQUEST pReq = (LPIOREQUEST)lpOver; // // エラーもデータもない場合は、 // 接続が閉じている // if (cbRecv == 0) { pReq->fFinished = TRUE; return; } fprintf(stderr,"\nRecvComplete(): %ld bytes received", cbRecv); // // 受信データをstdoutに書き込む // fwrite(pReq->pBuffer, cbRecv, 1, stdout); // // 受信バッファをもう一度指定する // WSABUF wsabuf; wsabuf.len = BUFFER_SIZE; wsabuf.buf = (char *)pReq->pBuffer; DWORD dwRecv; dwFlags = 0; int nRet; nRet = WSARecv(pReq->Socket, &wsabuf, 1, &dwRecv, &dwFlags, lpOver, RecvComplete); if (nRet == SOCKET_ERROR) { if (WSAGetLastError() != WSA_IO_PENDING) { PRINTERROR("RePost with WSARecv()"); pReq->fFinished = TRUE; } } }