質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

1691閲覧

WinSock2 IPv6のHTTPクライアント

Weapon

総合スコア106

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2019/05/05 15:10

前提・実現したいこと

WinSock2によるHTTPクライアントの作成を作成しようとしています.gethostname等では基本的にエラーが出ますし

  • IPv6
  • UNICODE

で書いていきたいと思い,GetAddInfo,ADDRINFOWを使っていますがconnectが失敗しWSA Error(WSAECONNREFUSED:10061)が返ってきます.
どのような原因が考えられるでしょうか.GetAddrInfoの引数はbig endianではないですよね?
入力するGetAddrInfoへのhostnameにhost以上のパスが含まれる場合や"http"が含まれる場合にもエラーになりますか?

該当のソースコード

スレッドのソケット系の箇所のコードになります.2行目でメインスレッドからパスを取得しています.
WSAStartup等の大きなエラーチェックは省略しています.

C

1#define UNICODE 2#include <windowsx.h> 3#include <WinSock2.h> 4#include <ws2tcpip.h> 5#include <process.h> 6 7{ 8 LPCWSTR turl = tph->lpURL;//url from main thread 9 LPCWSTR pnum = L"80";//http 10 11 /* Initialization of WinSocket */ 12 WSADATA wsad; 13 int err_wsas = WSAStartup(MAKEWORD(2, 0), &wsad); 14 if (err_wsas != 0) MYLOCALERROR 0x00010000; 15 16 /* END Initialization of WinSocket */ 17 18 /* DNS Name Resolution from Host */ 19 ADDRINFOW* ai; 20 ADDRINFOW hint = { 0 }; 21 22 ZeroMemory(&hint, sizeof(ADDRINFOW)); 23 hint.ai_socktype = SOCK_STREAM; 24 hint.ai_family = AF_INET; 25 26 int err_gai = GetAddrInfo(turl, pnum, &hint, &ai); 27 if (err_gai != 0) MYLOCALERROR 0x00020000; 28 29 /* END DNS Name Resolution from Host */ 30 31 wchar_t art[1024]; 32 wsprintf(art, L"ADDRIN\r\nSOCKADDR : %p\r\nsize : %d\r\n", ai->ai_addr, ai->ai_addrlen); 33 SetWindowText(tph->harticle, art); 34 35 /* Open Socket */ 36 SOCKET s; 37 s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 38 if (s == INVALID_SOCKET) { 39 MessageBox(thwnd, L"INVALID_SOCKET", L"socket", MB_OK); 40 WSACleanup(); 41 MYLOCALERROR = 0x00110001; 42 break; 43 } 44 /* END Open Socket */ 45 46 /* Connecting */ 47 48 int c = connect(s, ai->ai_addr, ai->ai_addrlen); 49 if (c != 0) 50 { 51 int wer = WSAGetLastError(); 52 wchar_t wsagerr[128]; 53 wsprintf(wsagerr, L"ERR CODE : %d\n",wer); 54 MessageBox(thwnd, wsagerr, L"connect", MB_OK); 55 MYLOCALERROR = 0x00040001; 56 break; 57 } 58 /* END Connecting */ 59 60 /* Send */ 61 int sndstatus = send(s, "GET /index.html HTTP/1.0\r\n\r\n", strlen("GET /index.html HTTP/1.0\r\n\r\n"), 0); 62 63 if (sndstatus > 0) 64 { 65 MessageBox(thwnd, L"Success", L"send", MB_OK); 66 MYLOCALERROR = 0x00050001; 67 break; 68 } 69 70 /* END Send */ 71 72 FreeAddrInfo(ai); 73 74 75 WSACleanup(); 76 EnableWindow(tph->hurl, TRUE); 77 EnableWindow(tph->hbrowse, TRUE); 78 }

補足情報

Windows10 Pro
VisualStudio2019 Community

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yumetodo

2019/05/05 16:57

>入力するGetAddrInfoへのhostnameにhost以上のパスが含まれる場合や"http"が含まれる場合にもエラーになりますか? 常識的にはエラーでしょうが、果たしてどういう仕様だったか・・・、MSDNみても書いていないし。
atata0319

2019/05/05 18:01 編集

>入力するGetAddrInfoへのhostnameにhost以上のパスが含まれる場合や"http"が含まれる場合にもエラーになりますか? そこを疑っているのであれば、httpを含めずに試した結果を記載していただいた方が良いかと思います。このコード断片だけで、どのような引数を渡しているかを類推するのは回答者には不可能です。
guest

回答1

0

自己解決

ご指摘があった通り

LPCWSTR turl = tph->lpURL;//url from main thread

がスレッドの引数リストの代入に失敗しておりNULLでした.

引数リストのLPWSTRに代入する段階でmallocで領域確保せず直接文字列ポインターを代入していました.文字列ポインターの使い方をあまり理解していなかったのが原因です.
またhostnameに関しては"http://"が付いていても最後に"/"(index)がついててもエラーになるのですね.
IPv6の特にUNICODE関数だと情報が交錯してわからないことが多いので今後ともよろしくお願いします.

投稿2019/05/05 23:30

Weapon

総合スコア106

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2019/05/06 01:01 編集

URLとhostname(接続先ホスト名)を混同されているのだと思います。 URL、例えば"http://hostname/path/”" だと、リモートの接続先はhostname部分を指しますし、IPアドレスの場合もあります。getaddrinfoはその部分だけを解釈します。 > "http://”" --> URLスキームと言って、hostnameとは意味するところが違います。 > "/"(index)が --> PATHを示す部分で、これまたhostnameとは意味するところが違います。
Weapon

2019/05/06 04:45

つまり実際のブラウザではURLスキームを見てhttpだったら80 httpsだったら443とport numberを定めhostnameでconnectされたらPath部分からファイルを取得しているということですか サンプルだとhostname port pathをそれぞれ別に入力するようになっていることが多いので実際のフォームとの違いに戸惑います
atata0319

2019/05/06 04:58

ポート番号の指定はホスト名の後に指定します。URL だと http://host:port/path/ という感じですね。port が指定されていない場合、デフォルトのポート番号は getservbyname で取得します。 あと、テスト用のコードでインターネットに公開されているサーバに直接接続するのはやめておきましょう。不正リクエストと判断される可能性があります。ローカル環境で apache 等でテスト用サイトを立ててください。また、そうでないと IPv6 が通信経路で遮断されている場合、IPv6 通信ではなくなってしまいます。
Weapon

2019/05/06 05:21

ではスキームは chrome://settings/ などの独自の実装しない限り無視ということでいいですか?わざとhttpでつなげたいときにhttpsからs取ってつながる場合もある気がするのですが あと話が少し戻りますがお二人の言うhostnameは"host+domain"でいいですか テスト環境すこし敷居上がりますねやってみます.
atata0319

2019/05/06 07:19

> ではスキームは chrome://settings/ などの独自の実装しない限り無視ということでいいですか? これは自作ソフトなので好きに決めていただいて問題ありません。API として手段が用意されていることをお伝えしたのみです。 > わざとhttpでつなげたいときにhttpsからs取ってつながる場合もある気がするのですが この辺は実際のサイトに接続できるようになった後だとわかるかと思いますが、サーバ側から http にリダイレクトするような応答が返ってきているはずです。ただ、通常は http から https へのリダイレクトの方が多いとは思います。 > あと話が少し戻りますがお二人の言うhostnameは"host+domain"でいいですか どのように解釈していただいても良いですが、GetAddrInfo から正常に結果が返ってくる名前となります。hosts ファイルに登録したり、DNS に登録しておけば、domain 部分はなしでも GetAddrInfo は結果を返してくれます。ただし、HTTP/1.1 以降を扱おうとすると host ヘッダが必須となるので、必然的に GetAddrInfo に渡す値は "host+domain" になるかと思います。この辺はもうちょっと学習が進んでから検証していただければ良いかと思います。
dodox86

2019/05/06 07:25 編集

> つまり実際のブラウザではURLスキームを見てhttpだったら80 httpsだったら443とport numberを定めhostnameでconnectされたらPath部分からファイルを取得しているということですか そういうことになります。ブラウザを含めたhttpクライアントは、例えば"http://host:8080/index.html" でアクセスする場合、名称"host"で解決できるIPアドレスに対してTCPポート8080番で接続し、"GET /index.html HTTP/1.1" (その他の付帯情報も含め) のHTTPリクエストを構築して送信するようにプログラムする、と言うことです。サーバー側ではHTTPリクエスト中のPATH部分を認識して、適切なレスポンスを返します。プロキシーサーバーを除き、URLスキーム部分を意識して制御を変えるのはクライアント側の仕事です。 > あと話が少し戻りますがお二人の言うhostnameは"host+domain"でいいですか 絶対そうだとは限りません。socketやconnectなどの比較的低レベルなソケットのAPIですと、接続先(リモート)を意識し、最終的にIPアドレスに収束しますが、hostnameと言うのは例で、ドメイン名までついているFDQNでもなんでも、hostsファイルやDNSを介して解決されます。ドメイン名が無い単なるホスト名でも、IPアドレスに解決されるならそこへconnectします。
atata0319

2019/05/06 07:23

現在のコードをどれぐらい実装できれば、インターネット側のサーバに接続して良いかの判断ですが、最低限 400 Bad Request が返されなくなるまでは作りこんでください。 https://developer.mozilla.org/ja/docs/Web/HTTP/Status/400 新しいヘッダを追加したり HTTP のバージョンを上げたりした場合はローカルで確実にテストしておくことをお勧めします。
dodox86

2019/05/06 07:24

あ、atata0319さんと重なってしまった。。。一見矛盾するコメントになってしまいましたが、取り上げている視点が違うだけだと思うので、決して矛盾しているわけではありません。
Weapon

2019/05/06 12:18

お二人ともありがとうございます.今後の参考にさせていただきます.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問