Win32/64ネットワーク開発 004 winsockを使ったhttp通信
前の記事:Win32/64ネットワーク開発 003 wininetを使ったftp通信
次の記事:[[Win32/64ネットワーク開発 005]]
概要
WinSockという通信の窓口を使って、ネットワークを通信してみたいと思います。自分ではネットワークの基礎となる装置を作るのは大変なのでWindowsではコレを使うのが最も基礎的なネットワークのプログラムを始める原点になると思います。
まずはhttp通信を処理するプログラムを作りますが、今はhttpsという通信が主要なので、あまり役に立たないですね。でも、https通信を行うとなると一気に難しくなります。httpsはSSL(Secure Socket Layer)やTLS(Transport Layer Security)という暗号方式で通信を行います。暗号通信おそるべし。そしてftpにもSSLがあります。ftpsですね。リモートにあるサーバを端末から操作する際、通信される一切の情報を暗号化するSSH(Secure SHell)を使ったSFTPもあるか。UNIX系のシェルが備えられている場合に使われるSCP(Secure Copy Protocol)もあるね。いろいろあります。ネットワーク通信楽しいけど、通信の道を出歩くときはちゃんと装備をして出歩かないと、街で強盗に合うような、通信の傍受をされることもあります。悪いことをする人がいなくなるといいんだけど、不平不満がなくならない世界に悪はなくならない。我慢が足りない人はたくさん存在するし、裕福な人の生活があり、そこをうらやむ人がいて、埋めようとする人がいる。ソフトウェアの勉強でもして人生を消費するのも楽しいのにね。Windows/Linux/Macパソコンがあるだけで裕福だと思うし、ましてや電力契約・ネットワーク通信契約が存在する環境があるなんて裕福過ぎる。スマホだと開発はあまりできないから、SNSに時間を消費したり暇になっちゃうかな。ここの管理人はSNSはやらないっすけどね。使い方だけちょろっと知って、あとはそっとしておくっす。
なんにしても、複雑なことをする前に、風前の灯となりつつあるHTTP通信の習得からですね。
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <Windows.h>
#include <cstdio>
#include <winsock2.h>
#include <iostream>
#include <string>
#pragma comment( lib, "ws2_32.lib" )
int main()
{
WSADATA WSADATAwsaData;
LPHOSTENT LPHOSTENTlpHostnet;
SOCKET SOCKETs;
int iReturn;
SOCKADDR_IN SOCKADDR_INsockadd;
char szServer[256], szURL[256], szStrRcv[1024], szPort[8], szYesNo[4];
wchar_t wchStr[256];
u_short u_shortPort;
unsigned int uiAddr;
while (1) {
if (WSAStartup(MAKEWORD(1, 1), &WSADATAwsaData) != 0) {
perror("WSAStartupエラー\n");
return -1;
}
printf("Webサーバー名(ex.www.yo-net.jp):");
std::cin >> szServer;
printf("ポート番号(ex.80):");
std::cin >> szPort;
if (strcmp(szPort, "") == 0) {
strcpy_s(szPort, strlen("80"), "80");
}
u_shortPort = (u_short)atoi(szPort);
printf("URL(ex.http://www.yo-net.jp/index.html):");
std::cin >> szURL;
if (strcmp(szURL, "") == 0){
strcpy_s(szURL, strlen("/"), "/");
}
//ソケット処理
SOCKETs = socket(PF_INET, SOCK_STREAM, 0);
if (SOCKETs == INVALID_SOCKET) {
perror("ソケットをオープンできない。\n");
WSACleanup();
return -2;
}
//ホスト情報取得処理
LPHOSTENTlpHostnet = gethostbyname(szServer);
if (LPHOSTENTlpHostnet == NULL) {
uiAddr = inet_addr(szServer);
LPHOSTENTlpHostnet = gethostbyaddr((char*)&uiAddr, 4, AF_INET);
if (LPHOSTENTlpHostnet == NULL) {
int iUTF16Len = MultiByteToWideChar(932, 0, szServer, -1, NULL, 0);
std::wstring wstringCP932Str(iUTF16Len, 0);
if (iUTF16Len > 0) {
MultiByteToWideChar(932, 0, szServer, -1, &wstringCP932Str[0], iUTF16Len);
}
wsprintf(wchStr, L"%sが見つからない\n", wstringCP932Str.c_str());
int iCP932Len = WideCharToMultiByte(932, 0, wchStr, -1, NULL, 0, NULL, NULL);
std::string stringCP932Str(iCP932Len, 0);
if (iCP932Len > 0) {
WideCharToMultiByte(932, 0, wchStr, -1, &stringCP932Str[0], iCP932Len, NULL, NULL);
}
perror(stringCP932Str.c_str());
WSACleanup();
return -3;
}
}
//SOCKADDR型構造体への値設定処理
memset(&SOCKADDR_INsockadd, 0, sizeof(SOCKADDR_INsockadd));
SOCKADDR_INsockadd.sin_family = AF_INET;
SOCKADDR_INsockadd.sin_port = htons(u_shortPort);
SOCKADDR_INsockadd.sin_addr = *((LPIN_ADDR)*LPHOSTENTlpHostnet->h_addr_list);
//接続処理
if (connect(SOCKETs, (PSOCKADDR)&SOCKADDR_INsockadd, sizeof(SOCKADDR_INsockadd)) != 0) {
perror("サーバーソケットに接続失敗\n");
closesocket(SOCKETs);
WSACleanup();
return -4;
}
//送信メッセージ形成処理
int iUTF16Len = MultiByteToWideChar(932, 0, szURL, -1, NULL, 0);
std::wstring wstringCP932Str(iUTF16Len, 0);
if (iUTF16Len > 0) {
MultiByteToWideChar(932, 0, szURL, -1, &wstringCP932Str[0], iUTF16Len);
}
wsprintf(wchStr, L"GET %s HTTP/1.0\r\n\r\n", wstringCP932Str.c_str());
int iCP932Len = WideCharToMultiByte(932, 0, wchStr, -1, NULL, 0, NULL, NULL);
std::string stringCP932Str(iCP932Len, 0);
if (iCP932Len > 0) {
WideCharToMultiByte(932, 0, wchStr, -1, &stringCP932Str[0], iCP932Len, NULL, NULL);
}
//送信処理
iReturn = send(SOCKETs, stringCP932Str.c_str(), (int)strlen(stringCP932Str.c_str()), 0);
//受信処理 受信最終文字までループ継続
while (1) {
memset(szStrRcv, '\0', sizeof(szStrRcv));
iReturn = recv(SOCKETs, szStrRcv, (int)sizeof(szStrRcv) - 1, 0);
printf("%s", szStrRcv);
if (iReturn == 0){
break;
}
if (iReturn == SOCKET_ERROR) {
perror("recvエラー\n");
break;
}
}
//終了処理 シャットダウン→クローズ→WSAクリア
if (shutdown(SOCKETs, SD_BOTH) != 0) {
perror("ソケットシャットダウン失敗\n");
}
closesocket(SOCKETs);
WSACleanup();
//プログラム継続判定
printf("\n再実行(Y/N):");
std::cin >> szYesNo;
if (strcmp(szYesNo, "n") == 0 || strcmp(szYesNo, "N") == 0){
break;
}
}
return 0;
}
上記のコードはコマンドプロンプトで動くコンソールアプリケーションです。プロジェクトのプロパティでリンカーの入力の追加の依存ファイルに;WSock32.lib;ws2_32.libを追加しなければなりません。
では少しづつ、動きを確認してみましょう。
1行目の#define WIN32_LEAN_AND_MEANがある場合Windows.hから以下のインクルードが除外されます。
- #include <cderr.h>
- include <dde.h>
- include <ddeml.h>
- include <dlgs.h>
- include <lzexpand.h>
- include <mmsystem.h>
- include <nb30.h>
- include <rpc.h>
- include <shellapi.h>
- include <winperf.h>
- include <winsock.h>
- include <wincrypt.h>
- include <winefs.h>
- include <winscard.h>
- include <winspool.h>
- include <ole2.h>
- include <commdlg.h>
前の記事:Win32/64ネットワーク開発 003 wininetを使ったftp通信
次の記事:[[Win32/64ネットワーク開発 005]]