【问题标题】:How to receive the response of a server into a string variable using c++?如何使用 C++ 将服务器的响应接收到字符串变量中?
【发布时间】:2016-04-02 16:26:41
【问题描述】:

我正在使用带有套接字的 c++ 编写控制台应用程序。我需要将响应接收到不是字符数组而是字符串中。问题是我不知道该怎么做。有人知道答案吗?谢谢大家。

现在我有了这个代码:

    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;
        }
    }

我需要在接收数据之前将 buffer 转换为字符串,因为如果我使用 char 数组,则缓冲区不足以存储整个结果,如果我增加大小,Visuale Studio 显示套接字初始化错误

我用:

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);

这是因为我需要将响应存储到字符串中,但是:我该怎么做?

【问题讨论】:

    标签: c++ visual-studio sockets visual-studio-2015 winsock


    【解决方案1】:

    好吧,让我们理智一点,摆脱那个可笑的巨大缓冲区。

    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
    

    【讨论】:

    • 但对于 copy_ifback_inserterisspace 我应该包括哪些库? @RichardHodges
    【解决方案2】:

    像这样在循环中连接(连接)string variablechar buffer

     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;
    }
    

    【讨论】:

    • 你因为提出了一个完整的、有效的示例和预期的结果而得到了我的 +1;即使您通过使用原始的 new/delete 代替智能指针犯了大罪……但出于某种原因,OP 似乎想从他的结果中删除空白。
    • @Software_Designer 您的代码可以工作,但是如果我插入路径以获取整个页面,则整个页面不会到达.. 我这样说:strcpy(getHttp, "GET /cerca?q=pasta HTTP/1.1\r\nHost: ");
    【解决方案3】:

    假设存储空间是实际问题,则链式缓冲区方法可能是一种解决方案。

    #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;
        }
    
    }
    

    【讨论】:

      【解决方案4】:

      你可以用这个:

      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),所以您必须确保分配了内存。在这里,我使用std::stringresize() 函数来确保字符串中有足够的内存。并且填充字符串后,您必须手动调整字符串大小。

      但是 recv 是一个普通的旧 C 函数,所以它根本无法自行调整 std::string 的大小!

      另一种解决方案是分配小 char 数组并将其连接到包含全局响应的最终 std::string :

      std::final final;
      
      // retrieve small char array of max_size, for example equal to 256
      
      final += std::string (buffer, max_size);
      

      【讨论】:

      • std::string::reserve 保留空间但不更改字符串的length()。第一个答案不正确。
      • 还是不对。 buffer 是默认构造的。在它上面调用 reserve() 不会改变任何事情。它的长度仍然为零。寻址 *(&buffer[0]) [which recv will do] 因此是未定义的行为。
      • @RichardHodges 再次更正,希望现在很好。非常感谢您的指正!
      • 这样就解决了。仍然 - 虽然有一百万个字符......你还没有考虑到操作想要删除空白的事实。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-03
      • 1970-01-01
      • 2019-03-03
      • 1970-01-01
      • 1970-01-01
      • 2023-02-14
      • 1970-01-01
      相关资源
      最近更新 更多