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

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

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

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

Q&A

解決済

1回答

1086閲覧

winsockでのFTPファイル受信で失敗してしまう

moritaro

総合スコア10

C++

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

0グッド

0クリップ

投稿2018/11/13 10:50

前提・実現したいこと

WindowsPCからUnixPCに対してファイル送受信できるFTPクライアントソフトをC++で作成したい

発生している問題・エラーメッセージ

当初、CFtpConnectionクラスを使用しアプリケーションを作成しました。
アプリケーションは完成したのですが、下記の条件が必要となりました。
1)ログイン失敗においても"QUIT"を送信しなければいけない
2)getコマンドでは"SIZE"を送信してはいけない
CFtpConnectionクラスを使用する場合"QUIT"はcommandメソッドを使用して送信していましたが、CInternetSessionクラスのGetFtpConnectionメソッドで失敗した場合はcommandメソッドを実行できない
CFtpConnectionクラスのGetFileメソッドではSIZEを送信してしまうことから、CFtpConnectionクラスを使用することは諦めました。

そこで、Winsockを使用しアプリケーションを作成しようと試みましたがファイルの受信でうまくいきません。

ファイル受信のところで
125 Data connection already open;Transfer starting. 226 Transfer complete
と返信されますが、ファイルは受信できていません。

質問1:ファイル受信の問題点を教えてください。
質問2:当初のCFtpConnectionクラスを使用した場合でも1)2)の条件を満たす手法はありますでしょうか。
宜しくお願いします。

該当のソースコード

C++

1{ 2 // TODO: ここにコントロール通知ハンドラ コードを追加します。 3 CString dir = "C:\Test"; 4 if (_chdir(dir) != 0) return; 5 6 7 char szStrRcv[1024]; 8 char szStr[256]; 9 10 WSADATA wsaData; 11 12 WSAStartup(MAKEWORD(2, 0), &wsaData); 13 14 SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); 15 16 //接続 17 struct sockaddr_in adr; 18 adr.sin_family = AF_INET; 19 adr.sin_port = htons(21); 20 adr.sin_addr.S_un.S_addr = inet_addr("192.168.200.2"); 21 22 if (connect(sock, (struct sockaddr*)&adr, sizeof(adr))) { 23 closesocket(sock); 24 WSACleanup(); 25 return; 26 } 27 28 memset(szStrRcv, '\0', sizeof(szStrRcv)); 29 recv(sock, szStrRcv, sizeof(szStrRcv)-1, 0); 30 31 if (strncmp(szStrRcv, "220", 3) != 0) { 32 closesocket(sock); 33 WSACleanup(); 34 return; 35 } 36 37 //コマンド 38 CString user = "USER ftpuser\r\n"; 39 CString pass = "PASS ftppass\r\n"; 40 CString cwd = "CWD ./FTP\r\n"; 41 CString type = "TYPE A\r\n"; 42 CString get = "RETR FTP.TXT\r\n"; 43 44 //ユーザー 45 strcpy_s(szStr, sizeof(szStr), user); 46 send(sock, szStr, (int)strlen(szStr), 0); 47 48 memset(szStrRcv, '\0', sizeof(szStrRcv)); 49 recv(sock, szStrRcv, sizeof(szStrRcv)-1, 0); 50 51 if (strncmp(szStrRcv, "331", 3) != 0) { 52 goto CLOSE_QUIT; 53 } 54 55 //パスワード 56 strcpy_s(szStr, sizeof(szStr), pass); 57 send(sock, szStr, (int)strlen(szStr), 0); 58 59 memset(szStrRcv, '\0', sizeof(szStrRcv)); 60 recv(sock, szStrRcv, sizeof(szStrRcv)-1, 0); 61 62 if (strncmp(szStrRcv, "230", 3) != 0) { 63 goto CLOSE_QUIT; 64 } 65 66 //ディレクトリ移動 67 strcpy_s(szStr, sizeof(szStr), cwd); 68 send(sock, szStr, (int)strlen(szStr), 0); 69 70 memset(szStrRcv, '\0', sizeof(szStrRcv)); 71 recv(sock, szStrRcv, sizeof(szStrRcv)-1, 0); 72 73 if (strncmp(szStrRcv, "250", 3) != 0) { 74 goto CLOSE_QUIT; 75 } 76 77 //アスキーモード 78 strcpy_s(szStr, sizeof(szStr), type); 79 send(sock, szStr, (int)strlen(szStr), 0); 80 81 memset(szStrRcv, '\0', sizeof(szStrRcv)); 82 recv(sock, szStrRcv, sizeof(szStrRcv)-1, 0); 83 84 if (strncmp(szStrRcv, "200", 3) != 0) { 85 goto CLOSE_QUIT; 86 } 87 88 //バインド設定 89 struct sockaddr_in mine; 90 mine.sin_family = AF_INET; 91 mine.sin_port = htons(0); 92// mine.sin_addr.s_addr = INADDR_ANY; 93 int len = sizeof(sockaddr_in); 94 if (getsockname(sock, (struct sockaddr*)&mine, &len) < 0) { 95 goto CLOSE_QUIT; 96 } 97 unsigned long hi, low; 98 hi = (ntohs(mine.sin_port) >> 8) & 0xff; 99 low = ntohs(mine.sin_port) & 0xff; 100 101 //ポート 102 sprintf(szStr, "PORT %d,%d,%d,%d,%d,%d\r\n", 103 mine.sin_addr.S_un.S_un_b.s_b1, 104 mine.sin_addr.S_un.S_un_b.s_b2, 105 mine.sin_addr.S_un.S_un_b.s_b3, 106 mine.sin_addr.S_un.S_un_b.s_b4,hi, low); 107 send(sock, szStr, (int)strlen(szStr), 0); 108 109 memset(szStrRcv, '\0', sizeof(szStrRcv)); 110 recv(sock, szStrRcv, sizeof(szStrRcv)-1, 0); 111 112 if (strncmp(szStrRcv, "200", 3) != 0) { 113 goto CLOSE_QUIT; 114 } 115 116 //データコネクション 117 SOCKET sockdata = socket(AF_INET, SOCK_STREAM, 0); 118 119 struct sockaddr_in adrdata; 120 adrdata.sin_family = AF_INET; 121 adrdata.sin_port = htons(hi * 256 + low); 122// adrdata.sin_addr.s_addr = INADDR_ANY; 123 adrdata.sin_addr = mine.sin_addr; 124 125 if (bind(sockdata, (struct sockaddr*)&adrdata, sizeof(adrdata)) == SOCKET_ERROR) { 126 goto CLOSE_DATA; 127 } 128 129 if (listen(sockdata, SOMAXCONN) == SOCKET_ERROR) { 130 goto CLOSE_DATA; 131 } 132 133 SOCKET AcceptSocket; 134 AcceptSocket = accept(sockdata, NULL, NULL); 135 if (AcceptSocket == INVALID_SOCKET) { 136 goto CLOSE_DATA; 137 } 138 139 //ファイル受信 140 strcpy_s(szStr, sizeof(szStr), get); 141 send(sock, szStr, (int)strlen(szStr), 0); 142 143 memset(szStrRcv, '\0', sizeof(szStrRcv)); 144 recv(sock, szStrRcv, sizeof(szStrRcv)-1, 0); 145 if (strncmp(szStrRcv, "150", 3) != 0) { 146 goto CLOSE_DATA; 147 } 148 149CLOSE_DATA: 150 closesocket(sockdata); 151CLOSE_QUIT: 152 CString quit = "QUIT\r\n"; 153 strcpy_s(szStr, sizeof(szStr), quit); 154 send(sock, szStr, (int)strlen(szStr), 0); 155 156 closesocket(sock); 157 WSACleanup(); 158} 159

試したこと

補足情報(FW/ツールのバージョンなど)

VisualStudio2005

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

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

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

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

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

guest

回答1

0

自己解決

自己解決しました。

ファイルのデータを受信する必要がありました。
問題点がありまして、ファイル受信のところで
"125 Data connection alresdy open; Transfer starting"
"226 Transfer complete"
の2つのメッセージを受信してからデータを受信したいのですが、続けて上記2行を受信しようとすると226のところでrecv()すると返ってきません。(プログラムが進まない)
データ受信は別のスレッドで処理すればいいのでしょうか。

下記コードについて、改善点や不必要なコードなどあれば、ご指摘いただけますと助かります。

C++

1{ 2 // TODO: ここにコントロール通知ハンドラ コードを追加します。 3 4 char szStrRcv[1024]; 5 char szStr[256]; 6 char acepStr[256]; 7 8 WSADATA wsaData; 9 10 WSAStartup(MAKEWORD(2, 0), &wsaData); 11 12 SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); 13 14 //接続 15 struct sockaddr_in adr; 16 adr.sin_family = AF_INET; 17 adr.sin_port = htons(21); 18 adr.sin_addr.S_un.S_addr = inet_addr("192.168.200.2"); 19 20 if (connect(sock, (struct sockaddr*)&adr, sizeof(adr))) { 21 closesocket(sock); 22 WSACleanup(); 23 return; 24 } 25 26 memset(szStrRcv, '\0', sizeof(szStrRcv)); 27 recv(sock, szStrRcv, sizeof(szStrRcv)-1, 0); 28 29 if (strncmp(szStrRcv, "220", 3) != 0) { 30 closesocket(sock); 31 WSACleanup(); 32 return; 33 } 34 35 //コマンド 36 CString user = "USER ftpuser\r\n"; 37 CString pass = "PASS ftppass\r\n"; 38 CString cwd = "CWD ./FTP\r\n"; 39 CString type = "TYPE A\r\n"; 40 CString get = "RETR FTP.TXT\r\n"; 41 42 FILE *fp; 43 errno_t err; 44 CString filename = "C:\Test\FTP.TXT"; 45 46 //ユーザー 47 strcpy_s(szStr, sizeof(szStr), user); 48 send(sock, szStr, (int)strlen(szStr), 0); 49 50 memset(szStrRcv, '\0', sizeof(szStrRcv)); 51 recv(sock, szStrRcv, sizeof(szStrRcv)-1, 0); 52 53 if (strncmp(szStrRcv, "331", 3) != 0) { 54 goto CLOSE_QUIT; 55 } 56 57 //パスワード 58 strcpy_s(szStr, sizeof(szStr), pass); 59 send(sock, szStr, (int)strlen(szStr), 0); 60 61 memset(szStrRcv, '\0', sizeof(szStrRcv)); 62 recv(sock, szStrRcv, sizeof(szStrRcv)-1, 0); 63 64 if (strncmp(szStrRcv, "230", 3) != 0) { 65 goto CLOSE_QUIT; 66 } 67 68 //ディレクトリ移動 69 strcpy_s(szStr, sizeof(szStr), cwd); 70 send(sock, szStr, (int)strlen(szStr), 0); 71 72 memset(szStrRcv, '\0', sizeof(szStrRcv)); 73 recv(sock, szStrRcv, sizeof(szStrRcv)-1, 0); 74 75 if (strncmp(szStrRcv, "250", 3) != 0) { 76 goto CLOSE_QUIT; 77 } 78 79 //アスキーモード 80 strcpy_s(szStr, sizeof(szStr), type); 81 send(sock, szStr, (int)strlen(szStr), 0); 82 83 memset(szStrRcv, '\0', sizeof(szStrRcv)); 84 recv(sock, szStrRcv, sizeof(szStrRcv)-1, 0); 85 86 if (strncmp(szStrRcv, "200", 3) != 0) { 87 goto CLOSE_QUIT; 88 } 89 90 //バインド設定 91 struct sockaddr_in mine; 92 mine.sin_family = AF_INET; 93 mine.sin_port = htons(0); 94// mine.sin_addr.s_addr = INADDR_ANY; 95 int len = sizeof(sockaddr_in); 96 if (getsockname(sock, (struct sockaddr*)&mine, &len) < 0) { 97 goto CLOSE_QUIT; 98 } 99 unsigned long hi, low; 100 hi = (ntohs(mine.sin_port) >> 8) & 0xff; 101 low = ntohs(mine.sin_port) & 0xff; 102 103 //データコネクション 104 SOCKET sockdata = socket(AF_INET, SOCK_STREAM, 0); 105 106 struct sockaddr_in adrdata; 107 adrdata.sin_family = AF_INET; 108 adrdata.sin_port = htons(hi * 256 + low); 109// adrdata.sin_addr.s_addr = INADDR_ANY; 110 adrdata.sin_addr = mine.sin_addr; 111 112 if (bind(sockdata, (struct sockaddr*)&adrdata, sizeof(adrdata)) == SOCKET_ERROR) { 113 goto CLOSE_DATA; 114 } 115 116 if (listen(sockdata, SOMAXCONN) == SOCKET_ERROR) { 117 goto CLOSE_DATA; 118 } 119 120 //ポート 121 sprintf(szStr, "PORT %d,%d,%d,%d,%d,%d\r\n", 122 mine.sin_addr.S_un.S_un_b.s_b1, 123 mine.sin_addr.S_un.S_un_b.s_b2, 124 mine.sin_addr.S_un.S_un_b.s_b3, 125 mine.sin_addr.S_un.S_un_b.s_b4,hi, low); 126 send(sock, szStr, (int)strlen(szStr), 0); 127 128 memset(szStrRcv, '\0', sizeof(szStrRcv)); 129 recv(sock, szStrRcv, sizeof(szStrRcv)-1, 0); 130 131 if (strncmp(szStrRcv, "200", 3) != 0) { 132 goto CLOSE_DATA; 133 } 134 135 struct sockaddr_in adracep; 136 int acep_len = sizeof(adracep); 137 SOCKET AcceptSocket; 138 AcceptSocket = accept(sockdata, (struct sockaddr*)&adracep, &acep_len); 139 if (AcceptSocket == INVALID_SOCKET) { 140 goto CLOSE_DATA; 141 } 142 143 //ファイル受信 144 strcpy_s(szStr, sizeof(szStr), get); 145 send(sock, szStr, (int)strlen(szStr), 0); 146 147 memset(szStrRcv, '\0', sizeof(szStrRcv)); 148 recv(sock, szStrRcv, sizeof(szStrRcv)-1, 0); 149 150 if (strncmp(szStrRcv, "125", 3) != 0) { 151 goto CLOSE_DATA; 152 } 153 154 memset(acepStr, '\0', sizeof(acepStr)); 155 int get_len; 156 157 err = fopen_s(&fp, filename, "wb"); 158 int flen; 159 if (err == 0) { 160 do { 161 get_len = recv(AcceptSocket, acepStr, sizeof(acepStr), 0); 162 flen = fwrite(acepStr, sizeof(char), get_len, fp); 163 } while (get_len == sizeof(acepStr)); 164 } 165 if (fp) fclose(fp); 166 closesocket(AcceptSocket); 167 168 //ファイル大きいとファイル受信(RETR)の"125"の後のレシーブで返ってこない 169 //よってファイル受信が完了していからレシーブする 170 //これレシーブしないと"QUIT"の返信がとれない 171 memset(szStrRcv, '\0', sizeof(szStrRcv)); 172 recv(sock, szStrRcv, sizeof(szStrRcv)-1, 0); 173 174 if (strncmp(szStrRcv, "226", 3) != 0) { 175 goto CLOSE_DATA; 176 } 177 178CLOSE_DATA: 179 closesocket(sockdata); 180CLOSE_QUIT: 181 CString quit = "QUIT\r\n"; 182 strcpy_s(szStr, sizeof(szStr), quit); 183 send(sock, szStr, (int)strlen(szStr), 0); 184 185 memset(szStrRcv, '\0', sizeof(szStrRcv)); 186 recv(sock, szStrRcv, sizeof(szStrRcv)-1, 0); 187 188 if (strncmp(szStrRcv, "221", 3) != 0) { 189 //QUIT失敗時の処理 190 } 191 192 closesocket(sock); 193 WSACleanup(); 194} 195

投稿2018/11/16 10:54

moritaro

総合スコア10

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.51%

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

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

質問する

関連した質問