WinSock
- プログラミング > WinSock
WinSockとは、プログラミングの
Windowsに
用語 の注意
[この
初心者 むけのページ
[- リンク
先 のページ内容 導入 の方法 (Visual Studio関連 )通信 の全体 像 (bind とか)- コードの
基本 骨格 と概要 (#include <winsock2.h>
とか)
- リンク
とりあえずのコード
[とりあえず、
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
int main(int argc, char** argv)
{
WSADATA wsaData;
int iResult;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
struct addrinfo* result = NULL,
* ptr = NULL,
hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
#define DEFAULT_PORT "27015"
// Resolve the server address and port
iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed: %d\n", iResult);
WSACleanup();
return 1;
}
SOCKET ConnectSocket = INVALID_SOCKET;
// Attempt to connect to the first address returned by
// the call to getaddrinfo
ptr = result;
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("Error at socket(): %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Connect to server.
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
}
// Should really try the next address returned by getaddrinfo
// if the connect call failed
// But for this simple example we just free the resources
// returned by getaddrinfo and print an error message
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
return 0;
}
MSDN のページをもとに
「(int argc, char** argv) 」とは、C
さて、
struct addrinfo* result = NULL,
(
MSDNコード例 の解説
[MSDNの完成 形 プログラムの概要
[MSDNソースコードの予備
[文法 の解説
[WSAStartup
[WSAStartup が
つまり、もし
なので、
getaddrinfo()
[IPv4 のころは gethostbyname が
getaddrinfo()を
getaddrinfo() は
なお、 getaddrinfo() で
Linuxのソケットプログラミングにも
IPv4版
[コード
[とりあえず、
#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment( lib, "ws2_32.lib" )
int main(int argc, char** argv) {
// WinSockの初期 化 など
WSADATA data;
WSAStartup(MAKEWORD(2, 2), &data);
char hostname[20] = "www.yaahole.com"; // 架空 の企業 名
struct addrinfo hints, * res;
int err;
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_INET;
hints.ai_protocol = IPPROTO_TCP;
err = getaddrinfo(hostname, NULL, &hints, &res);
if (err != 0) {
return -1;
}
struct sockaddr_in* temp = (struct sockaddr_in*)(res->ai_addr);
struct in_addr nameaddr;
nameaddr.s_addr = (temp)->sin_addr.s_addr;
char destbuf_text[500];
inet_ntop(AF_INET, &(nameaddr.s_addr), destbuf_text, 100);
printf("IPアドレス %s \n", destbuf_text);
freeaddrinfo(res);
// WinSockの終了
WSACleanup();
}
実行 結果
[※
IPアドレス 123.△〇△.987.〇〇×
のような
※
- ※よくあるエラーの
場合 の対処 法
架空 の企業 名 のアドレスを、実際 の企業 のアドレスに置 き換 えること。上記 のアドレス書 き換 えのさい、まちがえて企業 名 にhttpまたはhttpsを間違 えてつけていないか確認 すること。httpもhttpsもつかないのが正 しい。
解説
[- ソケット
指定 時 のバージョン指定 など
WSAStartup(MAKEWORD(2, 2), &data);
のMAKEWORDというのは、この
なお、
WSAStartup(MAKEWORD(メジャーバージョン, マイナーバージョン), &data);
の
また、もし
WSAStartup(MAKEWORD(2, 0), &data);
のようにバージョン2.0を
あまり
廃止 された関数
さて、かつて inet_ntoa
というinet_ntop
に
- ソケット
構造 体
さて、それとは
nameaddr.s_addr = ((struct sockaddr_in*)(res->ai_addr))->sin_addr.s_addr;
は、
そしてgetaddrinfo(hostname, NULL, &hints, &res); の
struct sockaddr *ai_addr;
と
この sockaddr *ai_addr は
BSD
IPアドレス
inet_ntop(AF_INET6, &nameaddr.s_addr, destbuf_text, 100 );
とあるが、
inet_ntop(アドレスファミリ, & sockaddr_in構造 体 変数 ,単 なる入 れ物 用 の変数 ,書 き込 みの幅 );
のような
なお、むりやり sockaddr
inet_ntop(AF_INET6, (res->ai_addr), destbuf_text, 100 );
および
inet_ntop(AF_INET6, (res->ai_addr), destbuf_text, 100 );
は、まったく
なので、まず、 nameaddr.s_addr = ((struct sockaddr_in*)(res->ai_addr))->sin_addr.s_addr;
は、addrinfo
(res->ai_addr)
という
そして、
(struct sockaddr_in*)(res->ai_addr)
によって、addrinfo
さて、 sockaddr_in
(struct sockaddr_in*)(res->ai_addr)は、 sockaddr_in
備考
[- MAKEWORDについて
なお、もし、
WSAStartup(0x0002, &data);
と
なお、「0x」とは「16
WORDは、「16
なお、16
なので、1 WORD は、4×4=16より、1 WORD は16ビット
そして、1バイトは8ビットなので、つまりWORDとは2バイトである。
8ビットで0から256の
MAKEWORDマクロ で
なお、DWORD とは「16
ちなみに、0xでWSAStartupを
WSAStartup(0x上 2ケタがマイナーバージョン下 2ケタがメジャーバージョン, &data);
の
なので、
WSAStartup(0x0202, &data);
でもコンパイルが
WSAStartup(0x0200, &data);
では
ちなみに、
printf("%s\n", data.szDescription); // WinSock 2.0 printf("バージョン : %d.%d \n" , (BYTE)data.wHighVersion, (BYTE)(data.wHighVersion >> 8) ); // バージョン : 2.2
というコードをWinSockの >>
というのはシフト
WSAStartup(MAKEWORD(2, 2), &data);
の
WSAStartup(MAKEWORD(2, 2), &wsadata);
なら、
printf("%s\n", wsadata.szDescription); // WinSock 2.0
のようにコードが
WinSock 2.0 バージョン : 2.2
のように
IPv6対応 のgetaddrinfo()
[#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <stdlib.h>
#include <locale.h>
#define _WINSOCK_DEPRECATED_NO_WARNINGS // 古 い関数 をいくつか使 っているので。古 いのを置 き換 えできるなら不要 。
#define _CRT_SECURE_NO_WARNINGS
#pragma comment( lib, "ws2_32.lib" )
// Winsock用 パラメータ // ないとコンパイル時 にエラーになる。
// なぜだか、早 めに宣言 する必要 がある。
int status;
int numsnt;
int main(int argc, char** argv) {
// WinSockの初期 化 など
WSADATA data;
WSAStartup(MAKEWORD(2, 0), &data);
char hostname[20] = "www.yaahule.com"; // 架空 の企業 名
struct addrinfo hints, * res;
int err;
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_INET6;
hints.ai_protocol = IPPROTO_TCP;
err = getaddrinfo(hostname, NULL, &hints, &res);
if (err != 0) {
return -1;
}
// いっぺんに↓こう書 いても、コンパイルできない。いろいろアレンジしてもダメ。
// &nameaddr->sin6_addr = ((struct sockaddr_in6*)(res->ai_addr))->sin6_addr.s6_addr;
struct sockaddr_in6* nameaddr; // in6_addr 型 ではなく sockaddr_in6 に変 えること
nameaddr = (struct sockaddr_in6*)res->ai_addr;
char destbuf_text[500];
inet_ntop(AF_INET6, &(nameaddr->sin6_addr), destbuf_text, 200);
printf("IP v6 アドレス - %s\n", destbuf_text);
freeaddrinfo(res);
// WinSockの終了
WSACleanup();
}
socket() 関数
[socket()
そのため、
またsocket()
socket()
これら3つの
ソケット構造 体
[基本
[MSDNのコード
struct addrinfo *result
とありますが、
これは
さて、Windowsの
- ptr->ai_family について
ソケット
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
とあります。
「->
」はアロー
ポインタ ptr が
そしてWindowsの
よって、 ptr->ai_family により、addrinfo
hints
[hints
さて WindowsにかぎらずLinuxなどでも
しかしWinSockのこのコードの hints は
- ※ hintsは
結局 は addrinfo構造 体 の流用 なので、極端 な話 、もしかしたら hints変数 を作成 しなくてもソケット通信 できる可能 性 もあるが、しかし互換 性 などのため、hints変数 を残 すほうが望 ましいだろう。
ZeroMemory() というのは
ZeroMemory() の
外部 通信 の方法
[外部 通信 の原理
[HTTP通信
[telnet(テルネット) でのHTTP
WinInet
[Windowsでは、
- ※
分類 上 は、WinInet技術 は WinSock とは別 の分類 ではあるが、本 wikiでは説明 のレベルの都合 上 、WinSockの科目 内 でWinInet技術 についても説明 することにする。
- コード
例
#include <stdio.h>
#include <windows.h>
#include <wininet.h> // 当然 だが、wininet.h をインクルードしないと、wininet技術 を使 えない
#pragma comment(lib,"wininet.lib")
int main() {
// ハンドルの作成
HINTERNET hInet;
hInet = InternetOpen(TEXT("sample"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
// URLのオープン
HINTERNET hFile;
hFile = InternetOpenUrl(hInet,
TEXT("http://localhost/detarame.html"), // ここにアクセスしたいページ名 のURLなど
NULL, 0, INTERNET_FLAG_RELOAD, 0);
// ファイルの読 み込 みの事前 処理
DWORD readSizeMax = 1000; // 読 み取 りの上限 サイズ。仕様 により、DWORDと決 まっている。
char* outBuf; // 受信 物 を格納 。仕様 により、ポインタでなければならない
outBuf = (char*)GlobalAlloc(GPTR, 1000); // メモリの動的 確保 。これしないと文字 化 け「seikouフフフフフフ」以下 略 が発生
DWORD* realRead; // 実際 に読 み込 まれるサイズの格納 用
// 読 み込 みのループ
while (1) {
bool rVal = InternetReadFile(hFile, outBuf, readSizeMax, (DWORD*)&realRead);
if (rVal == true) {
break;
}
}
printf("%s\n", outBuf);
GlobalFree(outBuf); // さきほど動的 確保 したメモリの解放
// 終了 処理
InternetCloseHandle(hFile);
InternetCloseHandle(hInet);
return 0;
}
実行 結果
※ http://localhost/detarame.html のページ
たとえば、webブラウザで
seikou
のように
- ※ 2023
年 のwindows11でも問題 なく上記 コードは動作 する。
技術 解説
WinInetのHTTP
InternetOpenURL
でアクセス
そのInternetOpen
などが
InternetOpen
してからでないと、InternetOpenURL
を
さて、C
Win32APIではファイルハンドルというものが
InternetOpen
の
InternetCloseHandle
でクローズする。
GlobalAlloc
は、Windowsmalloc
のようなメモリ
seikouフフフフフフフフフフフフフフフ
メモリGlobalFree()
でメモリ
なお、mallocも、free()
メモリGlobalFree()
でメモリGlobalFree()
の
なお、もし GlobalAlloc(GPTR, 1000);
の malloc(1000);
に
malloc だと、GlobalAlloc
- その
他
マイクロソフトは、WinInetについてはサンプルコードのひとつも
その他 のコード例
[InternetReadFile の InternetReadFile(hFile, outBuf, readSizeMax, (DWORD*)&realRead);
の
なので、この
- コード
例
#include <stdio.h>
#include <windows.h>
#include <wininet.h> // 当然 だが、wininet.h をインクルードしないと、wininet技術 を使 えない
#pragma comment(lib,"wininet.lib")
int main() {
// ハンドルの作成
HINTERNET hInet;
hInet = InternetOpen(TEXT("sample"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
// URLのオープン
HINTERNET hFile;
hFile = InternetOpenUrl(hInet,
TEXT("http://localhost/detarame.html"), // ここにアクセスしたいページ名 のURLなど
NULL, 0, INTERNET_FLAG_RELOAD, 0);
// ファイルの読 み込 みの事前 処理
DWORD readSizeMax = 1000; // 読 み取 りの上限 サイズ。仕様 により、DWORDと決 まっている。
char* outBuf; // 受信 物 を格納 。仕様 により、ポインタでなければならない
outBuf = (char*)GlobalAlloc(GPTR, 1000); // メモリの動的 確保 。これしないと文字 化 け「seikouフフフフフフ」以下 略 が発生
DWORD* realRead; // 実際 に読 み込 まれるサイズの格納 用
// 読 み込 みのループ
while (1) {
bool rVal = InternetReadFile(hFile, outBuf, readSizeMax, (DWORD*)&realRead);
if ( (int)realRead <= 0) {
break;
}
}
printf("%s\n", outBuf);
GlobalFree(outBuf); // さきほど動的 確保 したメモリの解放
// 終了 処理
InternetCloseHandle(hFile);
InternetCloseHandle(hInet);
return 0;
}
※ windows11で
関連 ページ
[外部 リンク集
[ソケットプログラミングについての
そのため
- Windows ソケット (サイト
名 :Wisdomソフト) - winsockプログラミング:Geekなぺーじ
参考 文献
[- ^ 2021
年 8月 現在 、ZeroMemoryはObsolateで、SecureZeroMemory の使用 が推奨 されています(最適 化 で揮発 しません)。 ⇒ https://docs.microsoft.com/ja-jp/previous-versions/windows/desktop/legacy/aa366877(v=vs.85)