WinSock
- プログラミング>WinSock
WinSockとは, プログラミングの tế, Windowsでインターネット thông tín をするためのAPIなどである. webブラウザを tác thành したりしたい tràng hợp, このようなAPI ( ソケット thông tín API ) が tất yếu である. もし単にホームページを tác りたい tràng hợp には, Winsock は bất yếu である ( ホームページの tác り phương は, giản 単なものなら HTML を sử って tác れる ).
Windowsに hạn らず, UnixやLinuxなどでも, OSが đề cung している, ネット thông tín をするためのAPI quần を “ソケット” (socket)といい, ソケットを dụng いて thông tín を thật hiện することを “ソケット thông tín” などという.
Dụng ngữ の chú ý
[Biên tập]この khoa mục でいっている “クライアント” trắc のプログラムとは, たとえばwebブラウザそのもののようなプログラムである ( HTMLファイルのことではないので, hỗn đồng しないように ).
Sơ tâm giả むけのページ
[Biên tập]- リンク tiên のページ nội dung
- Đạo nhập の phương pháp (Visual Studio quan liên )
- Thông tín の toàn thể tượng (bind とか)
- コードの cơ bổn cốt cách と khái yếu (
#include <winsock2.h>
とか)
とりあえずのコード
[Biên tập]とりあえず, động くコード(MSDNCreating a Socket for the Clientなどにあるコードを繋げただけ)
#include<winsock2.h>
#include<ws2tcpip.h>
#include<stdio.h>
#pragma comment(lib, "Ws2_32.lib" )
intmain(intargc,char**argv)
{
WSADATAwsaData;
intiResult;
// Initialize Winsock
iResult=WSAStartup(MAKEWORD(2,2),&wsaData);
if(iResult!=0){
printf("WSAStartup failed: %d\n",iResult);
return1;
}
structaddrinfo*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();
return1;
}
SOCKETConnectSocket=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();
return1;
}
// 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();
return1;
}
return0;
}
MSDN のページをもとに tác thành したコードだが, しかしMSDNのサイトでは “int main(int argc, char** argv)” の dẫn sổ “(int argc, char** argv)” の bộ phân の thuyết minh が bạt けているのである.
“(int argc, char** argv)” とは, C ngôn ngữ giới ôi で quán dụng đích によく dụng いられる dẫn sổ であり, “プログラム仮 dẫn sổ” という. ( tường しくは『C ngôn ngữ / trung cấp giả hướng けの thoại đề #プログラム仮 dẫn sổ を trì つ quan sổ』を tham chiếu. )
さて, cấu tạo thể の bộ phân は,
struct addrinfo* result = NULL,
( dĩ hạ lược ) は, Windows sĩ dạng やあるいは quy cách か hà かでこう thư くと quyết まっているらしく, MSDNにもこう cấu tạo thể が thư いてあるので,
Đọc giả はそのまま thụ け nhập れてもらうしかない.
MSDNコード lệ の giải thuyết
[Biên tập]MSDNの hoàn thành hình プログラムの khái yếu
[Biên tập]MSDNソースコードの dư bị
[Biên tập]Thượng ký のMSDNのコードの dư bị を, chư bàn の sự tình のため, wikibooksでも bảo quản する.
Văn pháp の giải thuyết
[Biên tập]WSAStartup
[Biên tập]WSAStartup が thành công した tràng hợp, 0を phản す sĩ dạng である.
つまり, もし phản り trị が 0 でなければ, エラーである.
なので, 続くif văn で, phản り trị が 0 かどうかを kiến ている.
getaddrinfo()
[Biên tập]IPv4 のころは gethostbyname が sử われていたが hiện tại ではあまりサポートされておらず, 2010 niên dĩ hàng の hiện đại では đại わりに getaddrinfo() を sử うのが thôi thưởng されています. ( thượng thuật MSDNの hoàn thành hình コード lệ でも gethostbyname は sử われておらず, getaddrinfo() だけが sử われています. )
getaddrinfo()を sử うには winsock2 が tất yếu ですのでインクルードする tất yếu があります ( つまりバージョン1ではダメ ).
Tàn niệm ながら nhật bổn のネットにあるwinsockについての cổ い giải thuyết サイトでは gethostbyname でいまだに giải thuyết しているサイトもありますが, 単にそのサイトの tác giả が canh tân をサボっているだけなので vô thị しましょう.
getaddrinfo() は thành công したら phản り trị として 0 を phản khước します.
なお, getaddrinfo() で xác bảo されたメモリは freeaddrinfo() で giải phóng されます.
Linuxのソケットプログラミングにも đồng dạng の quan sổ がありますが, しかし sĩ dạng が vi diệu に dị なるので, đọc giả はwinsockプログラミングではwindows dụng のサイトを tham khảo にしましょう.
IPv4 bản
[Biên tập]コード
[Biên tập]とりあえず, hạ ký のようなコードで, サイトのドメイン danh から, IPv4 đối ứng のIPアドレスを tri ることが xuất lai ます. (※いきなりIPv6 đối ứng のコードを thư くのは nan しいので, まずIPv4 đối ứng のコードから thư こう. )
#include<stdio.h>
#include<winsock2.h>
#include<ws2tcpip.h>
#pragma comment( lib, "ws2_32.lib" )
intmain(intargc,char**argv){
// WinSockの sơ kỳ hóa など
WSADATAdata;
WSAStartup(MAKEWORD(2,2),&data);
charhostname[20]="www.yaahole.com";// giá không の xí nghiệp danh
structaddrinfohints,*res;
interr;
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;
}
structsockaddr_in*temp=(structsockaddr_in*)(res->ai_addr);
structin_addrnameaddr;
nameaddr.s_addr=(temp)->sin_addr.s_addr;
chardestbuf_text[500];
inet_ntop(AF_INET,&(nameaddr.s_addr),destbuf_text,100);
printf("IPアドレス %s\n",destbuf_text);
freeaddrinfo(res);
// WinSockの chung liễu
WSACleanup();
}
Thật hành kết quả
[Biên tập]※ giá không の xí nghiệp のIPアドレスですので, sổ tự はデタラメです. また, nhất bộ, phục tự にしています.
IPアドレス 123.△〇△.987.〇〇×
のような kết quả になる.
※ thượng ký コードは2023 niên のwindows11でも vấn đề なく động tác する.
- ※よくあるエラーの tràng hợp の đối 処 pháp
- Giá không の xí nghiệp danh のアドレスを, thật tế の xí nghiệp のアドレスに trí き hoán えること.
- Thượng ký のアドレス thư き hoán えのさい, まちがえて xí nghiệp danh にhttpまたはhttpsを gian vi えてつけていないか xác nhận すること. httpもhttpsもつかないのが chính しい.
Giải thuyết
[Biên tập]- ソケット chỉ định thời のバージョン chỉ định など
WSAStartup(MAKEWORD(2, 2), &data);
のMAKEWORDというのは, この tràng hợp, WinSockのバージョンが2.2であることを biểu している. あまり sĩ dạng の tường tế のハッキリしない quan sổ であるが, MSDNでこの quan sổ ( chính xác にはマクロ ) が sử われているので, それに従おう.
なお, sinh thành されるWinSockのバージョンは
WSAStartup(MAKEWORD(メジャーバージョン, マイナーバージョン), &data);
の thư thức である.
また, もし
WSAStartup(MAKEWORD(2, 0), &data);
のようにバージョン2.0を chỉ định しても, thật hành thời に sinh thành されるWinSockのバージョンは tự động đích に2.2のような thật hành thời の tối tân an định bản のバージョンになる.
あまり trọng yếu ではないので, tường しくは hậu thuật する.
- 廃 chỉ された quan sổ
さて, かつてinet_ntoa
という quan sổ があったが, これは2020 niên đại のVisual Studio では sử えないので,inet_ntop
に trí き hoán える tất yếu がある.
- ソケット cấu tạo thể
さて, それとは biệt kiện だが,
nameaddr.s_addr = ((struct sockaddr_in*)(res->ai_addr))->sin_addr.s_addr;
は, hà をやっているかというと, đại まかには, まず, getaddrinfo()の kết quả が cấu tạo thể res ( またはそのポインタ ) に nhập り,
そしてgetaddrinfo(hostname, NULL, &hints, &res); の đệ 4 dẫn sổ でアドレスを chỉ định した cấu tạo thể (&res)は, addrinfo cấu tạo thể というものに cách nạp される. そして, Windowsの tràng hợp, addrinfo cấu tạo thể は, yếu tố として
struct sockaddr *ai_addr;
と ngôn う yếu tố を trì つ sĩ dạng になっている. ( nhất phương, BSDでは, OPアドレス tình báo は sockaddr に hàm まないらしい. )
この sockaddr *ai_addr は cấu tạo thể のポインタなので, lợi dụng の tế にはアロー diễn toán tử ->で chỉ định しなければいけない ( なぜ cấu tạo thể そのものではなく cấu tạo thể のポインタなのか khí になるかもしれないが, quy cách などでそう quyết まってしまっているようなので, 従うしかない. Ngoại quốc のサイトを kiến ても, đồng dạng のコードである ).
Bổn lai のBSDなどのsockaddr と sockaddr_in は, vi いとして, あて tiên IPアドレスの tình báo を hàm んでいるかどうかの vi いがある. sockaddr は, その cấu tạo thể 変 sổ の nội bộ tình báo には, IPアドレスの tình báo を hàm まない. Nhất phương, sockaddr_in はIPアドレス tình báo を hàm む. なので, thượng ký コードでは, tối chung đích にIPアドレス tình báo を hàm む sockaddr_in に変 hoán しているわけである.
BSD bổn lai の sockaddr はIPアドレス tình báo を hàm まないが, Windowsでは sockaddr がなんらかの phương pháp でIPアドレス tình báo を hàm んでおり, ともかくWindowsでは sockaddr_in に変 hoán できるように thật trang をされている.
IPアドレス tình báo をテキスト văn tự hóa できる quan sổ inet_ntop が, sockaddr_in だけに đối ứng しているので, これに変 hoán しなけれんばならない.
inet_ntop(AF_INET6, &nameaddr.s_addr, destbuf_text, 100 );
とあるが,
inet_ntop(アドレスファミリ, & sockaddr_in cấu tạo thể 変 sổ, 単なる nhập れ vật dụng の変 sổ, thư き込みの phúc );
のような thư thức である.
なお, むりやり sockaddr cấu tạo thể の tình báo を dẫn sổ に nhập れてもコンパイルできてしまうが, まったく vi うIPアドレスが biểu kỳ されてしまう.
inet_ntop(AF_INET6, (res->ai_addr), destbuf_text, 100 );
および
inet_ntop(AF_INET6, (res->ai_addr), destbuf_text, 100 );
は, まったく kiến đương vi いのアドレスを biểu kỳ するだけである.
なので, まず,nameaddr.s_addr = ((struct sockaddr_in*)(res->ai_addr))->sin_addr.s_addr;
は, addrinfo cấu tạo thể の trung から, IPアドレス quan liên の yếu tố を bạt き xuất すために,
(res->ai_addr)
という hạng mục がある.
そして,
(struct sockaddr_in*)(res->ai_addr)
によって, addrinfo cấu tạo thể のメンバとしての sockaddr cấu tạo thể の tình báo を, độc lập した sockaddr_in cấu tạo thể のポインタとなるように転 tả している.
さて, sockaddr_in cấu tạo thể は, メンバ変 sổ として “sin_addr.s_addr” というのを trì つが,
(struct sockaddr_in*)(res->ai_addr)は, sockaddr_in cấu tạo thể ではなく, sockaddr_in cấu tạo thể のポインタ なので, なので, “sin_addr.s_addr” にアクセスしたい tràng hợp には, アロー diễn toán tử でアクセスしなければならない.
Bị khảo
[Biên tập]- MAKEWORDについて
なお, もし, mạo đầu の WSAStartup のコードを変えてしまって,
WSAStartup(0x0002, &data);
と変えてもコンパイルできてしまい, thật hành thời に biểu kỳ されるIPアドレスも tương thủ tiên のアドレスであるが ( ※ 2020 niên にVisual Studio 2019で xác nhận ), しかしMSDNでは thôi thưởng していない thư thức なので, MAKEWORDで thư いたほうが an toàn だろう.
なお, “0x” とは “16 tiến sổ で” という ý vị.
WORDは, “16 tiến sổ で4ケタ” の trị という ý vị.
なお, 16 tiến sổ の1ケタは, 4ビットである. ( 2×2×2×2=16なので. )
なので, 1 WORD は, 4×4=16より, 1 WORD は16ビット trường である.
そして, 1バイトは8ビットなので, つまりWORDとは2バイトである.
8ビットで0から256の sổ trị を tráp えるので, 2バイトだと0から65536の sổ trị を tráp える. つまり, WORDは0から65536の sổ trị を tráp える.
MAKEWORDマクロ で tác られるビット liệt も, 1 WORDである. なので, 16 tiến sổ で4ケタを chỉ định してもいいのである.
なお, DWORD とは “16 tiến sổ で8ケタ” である. つまりDWORDなら hợp kế 4バイトである. DWORDは4バイトなので 0から 4,294 967,296 の sổ trị を tráp える.
ちなみに, 0xでWSAStartupを trực tiếp chỉ định した tràng hợp,
WSAStartup(0x thượng 2ケタがマイナーバージョン hạ 2ケタがメジャーバージョン, &data);
の thư thức である. MAKEWORDで sinh thành した tràng hợp とは, マイナーバージョンとメジャーバージョンの thuận tự が nghịch なので, khí をつけよう.
なので,
WSAStartup(0x0202, &data);
でもコンパイルが thông るし, biểu kỳ されるIPアドレスも chính thường である.
Nhất phương,
WSAStartup(0x0200, &data);
では thật hành しても, IPアドレスが biểu kỳ されない.
ちなみに,
printf( "%s\n", data.szDescription); // WinSock 2.0 printf( "バージョン: %d.%d \n", (BYTE)data.wHighVersion, (BYTE)(data.wHighVersion >> 8) ); // バージョン: 2.2
というコードをWinSockの sinh thành dĩ hàng からクローズ tiền の nhậm ý の tràng sở に phó け túc すことで, バージョンを biểu kỳ すことができる.
>>
というのはシフト diễn toán. Thượng ký コード lệ の tràng hợp なら, hữu に8ビットのシフトをするという ý vị.
Thượng ký コード trung の “data” とは,
WSAStartup(MAKEWORD(2, 2), &data);
の đệ 2 dẫn sổ の&dataに do lai している. なので, もし dẫn sổ danh が biệt の danh tiền (たとえば wsadata)で, ソケット sinh thành thời のコードも
WSAStartup(MAKEWORD(2, 2), &wsadata);
なら,
printf( "%s\n", wsadata.szDescription); // WinSock 2.0
のようにコードが変わる.
Truy gia コードの biểu kỳ kết quả は,
WinSock 2.0 バージョン: 2.2
のように biểu kỳ される. バージョン2.2であっても, “WinSock 2.0” と biểu kỳ される.
IPv6 đối ứng のgetaddrinfo()
[Biên tập]Hạ ký コードでgetaddrinfoでIPv6でDNSサーバと thông tín できる.
#include<stdio.h>
#include<winsock2.h>
#include<ws2tcpip.h>
#include<windows.h>
#include<stdlib.h>
#include<locale.h>
#define _WINSOCK_DEPRECATED_NO_WARNINGS// cổ い quan sổ をいくつか sử っているので. Cổ いのを trí き hoán えできるなら bất yếu.
#define _CRT_SECURE_NO_WARNINGS
#pragma comment( lib, "ws2_32.lib" )
// Winsock dụng パラメータ // ないとコンパイル thời にエラーになる.
// なぜだか, tảo めに tuyên ngôn する tất yếu がある.
intstatus;
intnumsnt;
intmain(intargc,char**argv){
// WinSockの sơ kỳ hóa など
WSADATAdata;
WSAStartup(MAKEWORD(2,0),&data);
charhostname[20]="www.yaahule.com";// giá không の xí nghiệp danh
structaddrinfohints,*res;
interr;
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;
}
// いっぺんに↓こう thư いても, コンパイルできない. いろいろアレンジしてもダメ.
// &nameaddr->sin6_addr = ((struct sockaddr_in6*)(res->ai_addr))->sin6_addr.s6_addr;
structsockaddr_in6*nameaddr;// in6_addr hình ではなく sockaddr_in6 に変えること
nameaddr=(structsockaddr_in6*)res->ai_addr;
chardestbuf_text[500];
inet_ntop(AF_INET6,&(nameaddr->sin6_addr),destbuf_text,200);
printf("IP v6 アドレス - %s\n",destbuf_text);
freeaddrinfo(res);
// WinSockの chung liễu
WSACleanup();
}
socket() quan sổ
[Biên tập]socket() quan sổ の phản khước trị は, intではなく, SOCKET hình という chuyên dụng の hình である tất yếu があります.
そのため, sự tiền に SOCKET hình の変 sổ ConnectSocket を tuyên ngôn しています.
またsocket() quan sổ は thất bại すると INVALID_SOCKET という phản khước trị を phản します.
socket() quan sổ は3つの dẫn sổ を thủ ります.
これら3つの dẫn sổ の tổ み hợp わせで, thông tín phương pháp を chỉ định しています.
Đệ 1 dẫn sổ はアドレスファミリというものの chỉ định です.
ソケット cấu tạo thể
[Biên tập]Cơ bổn
[Biên tập]MSDNのコード trung に
struct addrinfo *result
とありますが,
これは kí にwindowsによって định nghĩa されている addrinfo cấu tạo thể についてのポインタ変 sổ result を tác thành する tuyên ngôn です ( Unixでも, cấu tạo thể の danh tiền は vi いますが, ソケット thông tín の chuyên dụng の cấu tạo thể が tối sơ から dụng ý されており, その cấu tạo thể の変 sổ を thư き hoán えることで thông tín する phương pháp です ).
さて, Windowsの thượng ký の tuyên ngôn では, addrinfo は tác thành されません ( なぜなら, すでにaddrinfo cấu tạo thể は tác thành されているので ).
- ptr->ai_family について
ソケット tác thành のコードで
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
とあります.
“->
”はアロー diễn toán tử というもので, cấu tạo thể のポインタ の メンバ にアクセスするときに sử います.
ポインタ ptr が xuất てきて ách giới ですが,
Đọc みとくと, ptr は単なる cấu tạo thể addrinf のポインタ変 sổ です.
そしてWindowsの kí に dụng ý している addrinfo cấu tạo thể には, すでに ai_family メンバがありますので 『ADDRINFOA (ws2def.h) - Win32 apps | Microsoft Docs』『ADDRINFOA structure』 ,
よって, ptr->ai_family により, addrinfo cấu tạo thể の ai_family メンバにアクセスできるのです.
hints
[Biên tập]hints quan liên の hạng mục にある AF_INET というのはIPv4のアドレスファミリですが, なぜかIPv6 thời đại の hiện đại でも lưu dụng されており, これで sắc 々と thông dụng します.
さて WindowsにかぎらずLinuxなどでも nhất bàn に hints では, thông tín phương pháp を chỉ định する tình báo が tráp われている sĩ dạng である.
しかしWinSockのこのコードの hints は単にaddrinfo から lưu dụng した cấu tạo thể 変 sổ である. Thật tế, MSDN の ADDRINFOA structure を kiến ると, ページ trung ほどにある ai_family の hạng mục nhất lãm の trung に “AF_INET” という hạng mục があります.
- ※ hintsは kết cục は addrinfo cấu tạo thể の lưu dụng なので, cực đoan な thoại, もしかしたら hints変 sổ を tác thành しなくてもソケット thông tín できる khả năng tính もあるが, しかし hỗ hoán tính などのため, hints 変 sổ を tàn すほうが vọng ましいだろう.
ZeroMemory() というのは chỉ định した変 sổ のメモリにゼロ 0 を thư き込む quan sổ hình APIマクロ[1].
ZeroMemory() の đệ 1 dẫn sổ は, 0を thư き込みたいインスタンスへのポインタ.
Đệ 2 dẫn sổ は 0 を thư き込む văn tự の trường さ.
Ngoại bộ thông tín の phương pháp
[Biên tập]Ngoại bộ thông tín の nguyên lý
[Biên tập]HTTP thông tín
[Biên tập]telnet(テルネット) でのHTTP thông tín についても, thượng ký リンク tiên にある.
WinInet
[Biên tập]Windowsでは, thật はWinSockを sử わずとも, HTTPやFTPなど, kí tồn の hữu danh な thông tín プロトコルに đối ứng した, giản lược đích に thông tín できる quan sổ を trì った quan sổ グループがWindowsには kí に dụng ý されており, たとえばWinInetと ngôn われる quan sổ グループがそのような mục đích のために dụng ý されている.
- ※ phân loại thượng は, WinInet kỹ thuật は WinSock とは biệt の phân loại ではあるが, bổn wikiでは thuyết minh のレベルの đô hợp thượng, WinSockの khoa mục nội でWinInet kỹ thuật についても thuyết minh することにする.
Hạ ký に, WinInetを dụng いたHTTP thông tín のコード lệ を kỳ す.
Hạ ký コードを thật nghiệm するには, sự tiền に XAMPP や Apache などの webサーバ を lập ち thượng げること. なおwindowsの tràng hợp, apacheを trực tiếp インストールするのは nan しいので, xamppをインストールするのが nhập môn đích である ( なお『PHP/ xác thật に động tác させるまで』にXAMPPなどの thiết định の giải thuyết あり ).
Thật nghiệm dụng のHTMLファイルには, detarame.html というHTMLファイルに, “seikou” ( thành công の ý vị ) という văn tự liệt が thư いてあるとする.
- コード lệ
#include<stdio.h>
#include<windows.h>
#include<wininet.h>// đương nhiên だが, wininet.h をインクルードしないと, wininet kỹ thuật を sử えない
#pragma comment(lib, "wininet.lib" )
intmain(){
// ハンドルの tác thành
HINTERNEThInet;
hInet=InternetOpen(TEXT("sample"),INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
// URLのオープン
HINTERNEThFile;
hFile=InternetOpenUrl(hInet,
TEXT("http://localhost/detarame.html"),// ここにアクセスしたいページ danh のURLなど
NULL,0,INTERNET_FLAG_RELOAD,0);
// ファイルの đọc み込みの sự tiền 処 lý
DWORDreadSizeMax=1000;// đọc み thủ りの thượng hạn サイズ. Sĩ dạng により, DWORDと quyết まっている.
char*outBuf;// thụ tín vật を cách nạp. Sĩ dạng により, ポインタでなければならない
outBuf=(char*)GlobalAlloc(GPTR,1000);// メモリの động đích xác bảo. これしないと văn tự hóa け “seikouフフフフフフ” dĩ hạ lược が phát sinh
DWORD*realRead;// thật tế に đọc み込まれるサイズの cách nạp dụng
// đọc み込みのループ
while(1){
boolrVal=InternetReadFile(hFile,outBuf,readSizeMax,(DWORD*)&realRead);
if(rVal==true){
break;
}
}
printf("%s\n",outBuf);
GlobalFree(outBuf);// さきほど động đích xác bảo したメモリの giải phóng
// chung liễu 処 lý
InternetCloseHandle(hFile);
InternetCloseHandle(hInet);
return0;
}
- Thật hành kết quả
※http://localhost/detarame.htmlのページ nội dung と đồng じ nội dung が, そのまま biểu kỳ される.
たとえば, webブラウザで thượng ký ページにアクセスした tràng hợp に “seikou” と biểu kỳ されるなら, thượng ký C++コードを thật hành した tế には, コマンドプロンプトで “seikou” と biểu kỳ される.
seikou
のように biểu kỳ される.
- ※ 2023 niên のwindows11でも vấn đề なく thượng ký コードは động tác する.
- Kỹ thuật giải thuyết
WinInetのHTTP thông tín の tràng hợp, ポート phiên hào などの chỉ định の tất yếu がない.
Chỉ định するのは, ほぼURLのみで, quan sổInternetOpenURL
でアクセス tiên URL を chỉ định する. “URLのどこからどこがドメイン danh か?” とか, ユーザーは ý thức の tất yếu がない.
その tha,InternetOpen
などが dụng ý されており, cát とC ngôn ngữ のファイル nhập xuất lực の phân 囲 khí に cận いようなユーザーフレンドリーな cảm じで thao tác できるように, マイクロソフトが sĩ dạng を tác っている.
Tiên にInternetOpen
してからでないと, quan sổInternetOpenURL
を sử えないハズである.
さて, C ngôn ngữ のファイル nhập xuất lực では, ファイルポインタというものを giới して, ファイルのOpenやcloseなどの処 lý をする.
Win32APIではファイルハンドルというものが dụng ý されており, ファイルポインタと tự たような sử いかたをする.
InternetOpen
の nội dung を, ファイルハンドルに bảo quản する.
Thông tín が chung わったら, sử dụng したファイルハンドルを phiến phó けるため, quan sổInternetCloseHandle
でクローズする.
GlobalAlloc
は, Windows đặc hữu の, メモリの động đích xác bảo の quan sổ. Tiêu chuẩn C ngôn ngữ でいうmalloc
のようなメモリ xác bảo の quan sổ である.
Bổn WinInet thông tín では thật trang の đô hợp などで, もしコレを sử わずに trực tiếp にchar hình の phối liệt に thụ tín した văn tự を cách nạp しようとしても, văn tự hóa けで
seikouフフフフフフフフフフフフフフフ
Dĩ hạ lược のように biểu kỳ されてしまう.
メモリ xác bảo したら, bổn lai なら, sử dụng が chung わったらGlobalFree()
でメモリ giải phóng しないといけない. なので, thượng ký コードでは, メモリ giải phóng してある.
なお, mallocも, free() quan sổ でメモリ giải phóng するのが, hành nghi よい, とされる. なぜなら, mallocなどのメモリ xác bảo の quan sổ を sử う tràng hợp, sử dụng hậu にはメモリ giải phóng をしないと, バグとして “メモリリーク” というメモリ áp bách のバグの nguyên nhân になりやすいからである.
メモリ xác bảo したら, bổn lai なら, sử dụng が chung わったらGlobalFree()
でメモリ giải phóng しないといけない. なので, thượng ký コードでは, メモリ giải phóng してある.
Thật は, この trình độ の trường さのコードの tràng hợp, Windowsが khí を lợi かして, コード chung liễu thời にメモリを giải phóng してくれるのでGlobalFree()
の tỉnh lược も khả năng である. だが kim hậu, biệt の trường いコードにコピーする tràng hợp など tương lai đích な học tập も khảo え, thượng ký コードではメモリを hành nghi よく giải phóng してある.
なお, もし単にGlobalAlloc(GPTR, 1000);
の bộ phân をそのままmalloc(1000);
に trí き hoán えても, Windowsの thật trang の đô hợp なのか, văn tự hóa け “seikouヘヘヘヘヘヘヘヘヘヘヘヘヘヘヘヘヘヘヘヘヘヘヘヘヘヘ” が xuất てしまう.
malloc だと, GlobalAlloc dẫn sổ の “GPRT” などのフラグ thiết định を xuất lai ない.
- その tha
マイクロソフトは, WinInetについてはサンプルコードのひとつも công thức MSDNに thiệu giới していない ( 2020 niên 7 nguyệt に xác nhận ). せっかくユーザフレンドリーなWinInetがあるのに, サービス tâm が trung đồ bán đoan である.
その tha のコード lệ
[Biên tập]InternetReadFile の sĩ dạng として, ファイルを đọc み chung わると,
InternetReadFile(hFile, outBuf, readSizeMax, (DWORD*)&realRead);
の tối hậu の dẫn sổ realRead に 0 が đại nhập される.
なので, この sĩ dạng を sử うことで, HTTP thông tín における thụ tín のwhileループを hạ ký のように thư き hoán えることもできる.
- コード lệ
#include<stdio.h>
#include<windows.h>
#include<wininet.h>// đương nhiên だが, wininet.h をインクルードしないと, wininet kỹ thuật を sử えない
#pragma comment(lib, "wininet.lib" )
intmain(){
// ハンドルの tác thành
HINTERNEThInet;
hInet=InternetOpen(TEXT("sample"),INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
// URLのオープン
HINTERNEThFile;
hFile=InternetOpenUrl(hInet,
TEXT("http://localhost/detarame.html"),// ここにアクセスしたいページ danh のURLなど
NULL,0,INTERNET_FLAG_RELOAD,0);
// ファイルの đọc み込みの sự tiền 処 lý
DWORDreadSizeMax=1000;// đọc み thủ りの thượng hạn サイズ. Sĩ dạng により, DWORDと quyết まっている.
char*outBuf;// thụ tín vật を cách nạp. Sĩ dạng により, ポインタでなければならない
outBuf=(char*)GlobalAlloc(GPTR,1000);// メモリの động đích xác bảo. これしないと văn tự hóa け “seikouフフフフフフ” dĩ hạ lược が phát sinh
DWORD*realRead;// thật tế に đọc み込まれるサイズの cách nạp dụng
// đọc み込みのループ
while(1){
boolrVal=InternetReadFile(hFile,outBuf,readSizeMax,(DWORD*)&realRead);
if((int)realRead<=0){
break;
}
}
printf("%s\n",outBuf);
GlobalFree(outBuf);// さきほど động đích xác bảo したメモリの giải phóng
// chung liễu 処 lý
InternetCloseHandle(hFile);
InternetCloseHandle(hInet);
return0;
}
※ windows11で thí したところ, realRead を (int) で変 hoán しないといけなかった. 変 hoán しないとビルドエラーになった.
Quan liên ページ
[Biên tập]Ngoại bộ リンク tập
[Biên tập]ソケットプログラミングについての xuất bản trạng huống は, まるで Visual C++ の Windows APIプログラミングの thư điếm での bất túc ぶりと loại tự の trạng huống であり, あまり thị phiến の nhập môn thư ではソケットプログラミングが giải thuyết されていない trạng thái である.
そのため đương diện はネットの giải thuyết サイトを tham khảo にするしかない.
Hạ ký のサイトに, sung thật したWinSockの giải thuyết がある.
- Windows ソケット( サイト danh:Wisdomソフト )
- winsockプログラミング:Geekなぺーじ
Tham khảo văn hiến
[Biên tập]- ^2021 niên 8 nguyệt hiện tại, ZeroMemoryはObsolateで, SecureZeroMemory の sử dụng が thôi thưởng されています ( tối thích hóa で huy phát しません ). ⇒https://docs.microsoft.com/ja-jp/previous-versions/windows/desktop/legacy/aa366877(v=vs.85)