2016-04-02 9 views
0

私は、ソケットでC++を使ってコンソールアプリケーションを書いています。私は文字列ではなく文字列に応答を受け取る必要があります。問題は私がそれをやる方法を知らないことです。誰かが答えを知っていますか?ありがとうございます。C++を使用して文字列変数にサーバーの応答を受け取る方法は?

今、私はこのコードをした:私はchar型の配列を使用する場合、バッファはentaireを格納するenought大きくないので

char buffer[1000000]; 
    int nDataLength; 
    while ((nDataLength = recv(Socket, buffer, 1000000, 0)) > 0) { 
     int i = 0; 
     while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') { 
      cout << buffer[i]; 
      i += 1; 
     } 
    } 

私は、データを受信する前に、文字列にバッファを翻訳する必要がありますその結果、私はサイズを増やす場合、Visualeメーカーは、私が使用ソケット

の初期化でエラーが表示さ:

WSADATA wsaData; 
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { 
     cout << "WSAStartup failed.\n"; 
     system("pause"); 
     return 1; 
    } 
    SOCKET Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    struct hostent *host; 
    host = gethostbyname("www.site.com"); 
    SOCKADDR_IN SockAddr; 
    SockAddr.sin_port = htons(80); 
    SockAddr.sin_family = AF_INET; 
    SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr); 

これは私が文字列にレスポンスを格納する必要がある方法です:どうすればいいですか?

答えて

1

を連結(合流)このようなあなたのループ内char bufferstring variable

myString+=buffer[i]; // myString = myString + buffer[i]; 

例コードリスト:

#include <winsock2.h> 
#include <windows.h> 
#include <iostream> 
#include <string> 
#include <locale> 
#pragma comment(lib,"ws2_32.lib") 
using namespace std; 

string myString; 
locale local; 


//*************************** 
void getWebsite(char *url); 
//*************************** 


int main(){ 


    getWebsite("www.google.com"); 
    for (size_t i=0; i<myString.length(); ++i) myString[i]= tolower(myString[i],local); 

    cout <<myString; 

    return 0; 
} 



//*************************** 
void getWebsite(char *url){ 
    WSADATA wsaData; 
    SOCKET Socket; 
    SOCKADDR_IN SockAddr; 


    int lineCount=0; 
    int rowCount=0; 

    struct hostent *host; 
    char *getHttp= new char[256]; 

     memset(getHttp,' ', sizeof(getHttp)); 
     strcpy(getHttp,"GET/HTTP/1.1\r\nHost: "); 
     strcat(getHttp,url); 
     strcat(getHttp,"\r\nConnection: close\r\n\r\n"); 

     if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0){ 
      cout << "WSAStartup failed.\n"; 
      system("pause"); 
      //return 1; 
     } 

     Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 


     host = gethostbyname(url); 

     SockAddr.sin_port=htons(80); 
     SockAddr.sin_family=AF_INET; 
     SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr); 

     cout << "Connecting...\n"; 
      if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) != 0){ 
       cout << "Could not connect"; 
       system("pause"); 
       //return 1; 
      } 
     cout << "Connected.\n"; 

     //send(Socket,"GET/HTTP/1.1\r\nHost: www.cplusplus.com\r\nConnection: close\r\n\r\n", strlen("GET/HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n"),0); 

     send(Socket,getHttp, strlen(getHttp),0); 

     char buffer[10000]; 

     int nDataLength; 
      while ((nDataLength = recv(Socket,buffer,10000,0)) > 0) {  
       int i = 0; 

       while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') { 

        myString+=buffer[i]; // myString = myString + buffer[i]; 
        i += 1; 
       } 


      } 
     closesocket(Socket); 
     WSACleanup(); 

     delete[] getHttp; 
} 

enter image description here

+0

あなたは、私から+1を得ています。スマートポインタの代わりに生のnew/deleteを使って枢機卿の罪を犯したとしても...何らかの理由で、OPは彼の結果から空白を削除したいようです。 –

+0

@ Software_Designerあなたのコードは動作しますが、ページ全体を取得するためにパスを挿入した場合、ページ全体が届かない..私はこれを言う: 'strcpy(getHttp、" GET/cerca?q = pasta HTTP/1.1 \ r \ nHost: ") ; ' –

0

あなたはこれを使用することができます:

const std::ssize_t max_size = 1000000; 
std::string buffer(); 
buffer.resize(max_size); 

// and use where you need: 
ssize_t new_size = recv(Socket, &buffer[0], max_size, 0); 
buffer.resize (new_size); 

std::stringが決まった大きさ(とnullの可能性)を持っていないので、あなたはメモリが割り当てられていることを確認する必要があります。ここでは、resize()の関数をstd::stringとし、文字列の中に十分なメモリがあることを確認します。文字列を埋めた後、手動で文字列のサイズを変更する必要があります。

BUT recvは単純な古いC関数なので、std::stringを単独でサイズ変更することはできません。実際問題は、連鎖バッファのアプローチがあり得るされる記憶空間を仮定

std::final final; 

// retrieve small char array of max_size, for example equal to 256 

final += std::string (buffer, max_size); 
+0

のstd ::文字列: :予約はスペースを予約しますが、文字列の 'length()'は変更しません。最初の答えは間違っています。 –

+0

@RichardHodgesが修正されました – Garf365

+0

まだ正しくはありません。バッファはデフォルトで構築されています。 reserve()を呼び出すと何も変わりません。それはまだ長さゼロです。したがって、アドレス指定*(&buffer [0])[recvは行いません]は未定義の動作です。 –

0

別の解決策は、小さな文字列を割り当て、グローバル応答が含ま最終のstd ::文字列に連結することです溶液。

#define MAX_BUF_LEN 10000 
typedef struct netBuf 
{ 
    char data[MAX_BUF_LEN]; 
    struct netBuf * pNext; 
} NET_BUF; 

NET_BUF * pHead = NULL; 
NET_BUF *pCurrent = malloc(sizeof(NET_BUF)); 
pCurrent->pNext = NULL: 
pHead = pCurrent; 

char * pData = pCurrent->data; 
int nDataLength; 
int dataToRead = MAX_BUF_LEN; 

while ((nDataLength = recv(Socket, pData, dataToRead, 0)) > 0) { 
    if(dataToRead == nDataLength) 
    { 
     pCurrent->pNext = malloc(sizeof(NET_BUF)); 
     pCurrent = pCurrent->pNext; 
     pCurrent->pNext = NULL; 
     pData = pCurrent->data; 
     dataToRead = MAX_BUF_LEN; 
    } 
    else 
    { 
     dataToRead -= nDataLength; 
     pData +=nDataLength; 
    } 

} 
2

大丈夫ですが、そのばかげた巨大なバッファを取り除きましょう。

char buffer[4096]; 
int nDataLength; 
std::string result; 
while ((nDataLength = recv(Socket, buffer, 4096, 0)) > 0) { 
    std::copy_if(buffer, buffer + nDataLength, 
       std::back_inserter(result), 
       [](char c) { 
        return !std::isspace(c); 
        // maybe you wanted this instead? 
        // return std::isprint(c); 
       }); 
} 
// result now contains your string, without any white space 
+0

ですが、 'copy_if'、' back_inserter'、 'isspace'にはどのライブラリを含めるべきですか? @RichardHodges –

関連する問題