2017-02-03 60 views
-2

我正在试飞一个飞利浦Hue的小项目,同时学习C++。我试图做的是在客户和桥之间进行代理。就任何客户而言,该应用程序都会作为桥梁运行,接收请求并将其传递到桥上。转发流量到另一个设备C++

我有一个奇怪的问题:当应用程序正常运行,我只得到一个HTTP 200 OK响应,没有别的,如果我通过代码一步,我得到充分的响应。

下面是我的代码,没有线程,没有课,所有的主要方法正在做。

WindowsSocket socketManager(&bitsLibrary); 


    if (!socketManager.createSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 80, 1024)) 
    { 
     cout << "Failed to create socket" << endl; 
    } 

    socketManager.bindAndStartListening(); 

    WindowsSocket bridgeSocketManager(&bitsLibrary); 



    while (true) 
    { 

     sockaddr_in clientAddr; 
     memset(&clientAddr, 0, sizeof(sockaddr_in)); 
     SOCKET clientSocket = socketManager.acceptClientAndReturnSocket(&clientAddr); 
     this_thread::sleep_for(chrono::milliseconds(500)); 
     string received = socketManager.receiveDataOnSocket(&clientSocket); 
     bitsLibrary.writeToLog(received); 

     struct sockaddr_in server; 
     server.sin_family = AF_INET; 
     //server.sin_addr.s_addr = inet_addr("139.162.223.149"); 
     server.sin_addr.s_addr = inet_addr("192.168.1.67"); 
     server.sin_port = htons(80); 
     bridgeSocketManager.createSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
     this_thread::sleep_for(chrono::milliseconds(500)); 
     int result = connect(*bridgeSocketManager.returnSocket(), (struct sockaddr *)&server, sizeof(server)); 
     if (result < 0) 
     { 
      cout << "Connect Failed: " << WSAGetLastError() << endl; 
      return EXIT_FAILURE; 
     } 
     this_thread::sleep_for(chrono::milliseconds(500)); 

     SOCKET * bridgeSocket = bridgeSocketManager.returnSocket(); 
     this_thread::sleep_for(chrono::milliseconds(500)); 
     socketManager.sendToSocket(bridgeSocket, received); 
     string reply = socketManager.receiveDataOnSocket(bridgeSocket); 

     //boost::replace_all(reply, "Host: 192.168.1.70", "Host: 192.168.1.67"); 
     bitsLibrary.writeToLog(reply); 
     this_thread::sleep_for(chrono::milliseconds(1000)); 
     int sent = socketManager.sendToSocket(&clientSocket, reply); 
     this_thread::sleep_for(chrono::milliseconds(500)); 
     bridgeSocketManager.closeSocket(); 
     this_thread::sleep_for(chrono::milliseconds(500)); 
     socketManager.closeSocket(&clientSocket); 
     /*while (true) 
     { 
      SOCKET clientSocket = socketManager.acceptClientAndReturnSocket(&clientAddr); 
      SocketProcessor socketProcessor; 
      socketProcessor.startThread(socketManager, clientSocket); 
     }*/ 
    } 
    socketManager.closeSocket(); 

我的套接字接收方法如下:

std::string WindowsSocket::receiveDataOnSocket(SOCKET *socket) 
{ 
    if (*socket != -1) 
    { 
     string receivedData = ""; 
     char *temp = NULL; 
     int bytesReceived = 0; 
     do 
     { 
      bytesReceived = recv(*socket, this->buffer, this->bufferLength, 0); 
      if (bytesReceived == SOCKET_ERROR) 
      { 
       string socketError = this->getErrorStringFromErrorCode(WSAGetLastError()).c_str(); 

       stringstream logstream; 
       logstream << "Failed to receive data on socket.The socket will now be closed and cleanup performed. Error: " << socketError; 

       this->bitsLibrary->writeToLog(logstream.str(), "WindowsSocket", "receiveDataOnSocket"); 
       closesocket(*socket); 
       WSACleanup(); 
       throw SocketException(socketError.c_str()); 
       return ""; 
      } 

      //If we got here, then we should be able to get some data 
      temp = new char[bytesReceived + 1]; 
      //memset(&temp, 0, bytesReceived + 1); 
      strncpy(temp, this->buffer, bytesReceived); 
      temp[bytesReceived] = '\0'; //Add a null terminator to the end of the string 
      receivedData.append(temp); 
      temp = NULL; 

      //Now clear the buffer ready for more data 
      memset(this->buffer, 0, this->bufferLength); 
      cout << "Bytes Received: " << bytesReceived << " BUffer Length: " << this->bufferLength << endl; 
     } while (bytesReceived == this->bufferLength && bytesReceived >= 0); //Keep going until the received bytes is less than the buffer length 

     return receivedData; 
    } 
    else 
    { 
     stringstream logstream; 
     logstream << "Can't receive on socket as already be closed"; 
     throw SocketException(logstream.str().c_str()); 
    } 
} 

send方法如下所示:

int WindowsSocket::sendToSocket(SOCKET *clientSocket, string dataToSend) 
{ 
    //dataToSend.append("\r\n"); 
    int sentBytes = send(*clientSocket, dataToSend.c_str(), dataToSend.length(), 0); 
    if (sentBytes == SOCKET_ERROR) 
    { 
     throw SocketException(this->getErrorStringFromErrorCode(WSAGetLastError()).c_str()); 
    } 
    return sentBytes; 
} 

当我正常运行的应用程序在Visual Studio中没有破发点我得到下面的输出:

03/02/2017 22:08:16: WindowsSocket/bindAndStartListening: Socket has binded and is now listening 
Bytes Received: 413 BUffer Length: 1024 
Receiving data 
GET /api/nouser/config HTTP/1.1 
Host: 192.168.1.70 
Connection: keep-alive 
Cache-Control: max-age=0 
Upgrade-Insecure-Requests: 1 
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 
Accept-Encoding: gzip, deflate, sdch 
Accept-Language: en-GB,en;q=0.8 

03/02/2017 22:08:22: BaseSocket/createSocket:  Creating buffer of length 1024 
Bytes Received: 17 BUffer Length: 1024 
03/02/2017 22:08:23: HTTP/1.1 200 OK 
Sent: 17 

如果我设置一个断点,然后通过代码我碰到下面的步骤:

03/02/2017 22:09:03: WindowsSocket/bindAndStartListening: Socket has binded and is now listening 
Bytes Received: 413 BUffer Length: 1024 
GET /api/nouser/config HTTP/1.1 
Host: 192.168.1.70 
Connection: keep-alive 
Cache-Control: max-age=0 
Upgrade-Insecure-Requests: 1 
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 
Accept-Encoding: gzip, deflate, sdch 
Accept-Language: en-GB,en;q=0.8 

03/02/2017 22:09:09: BaseSocket/createSocket:  Creating buffer of length 1024 
Bytes Received: 630 BUffer Length: 1024 
03/02/2017 22:09:17: HTTP/1.1 200 OK 
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 
Pragma: no-cache 
Expires: Mon, 1 Aug 2011 09:00:00 GMT 
Connection: close 
Access-Control-Max-Age: 3600 
Access-Control-Allow-Origin: * 
Access-Control-Allow-Credentials: true 
Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE, HEAD 
Access-Control-Allow-Headers: Content-Type 
Content-type: application/json 

{"name":"Philips hue","datastoreversion":"59","swversion":"01036659","apiversion":"1.16.0","mac":"00:17:88:1a:1f:43","bridgeid":"001788FFFE1A1F43","factorynew":false,"replacesbridgeid":null,"modelid":"BSB001"} 
Sent: 630 

通知时,我没有做一个破发点,我收到只有17字节HTTP的200 OK,但是当我断点和步骤通过代码,我可以获得超过600个字节并获得我期待的所有内容。

我看不出有什么问题,我已经把睡在期待这将“修复”的问题,但即使是睡觉没有什么区别。

感谢您提供的任何帮助。

+0

你的条件(bytesReceived == this-> bufferLength)是荒谬的 –

+0

阅读更多关于[HTTP](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol),这比你想象的更复杂。考虑使用一些HTTP服务器或HTTP客户端库。看看[libcurl](https://curl.haxx.se/libcurl/)(HTTP客户端)和[libonion](http://coralbits.com/libonion/)(HTTP服务器)。另请参阅[POCO](https://pocoproject.org/),[Boost](http://boost.org/)和[Qt](http://qt.io/)框架。 –

回答

2

send()/ recv()是低级调用来处理套接字。为了正确处理HTTP,这是一个非常复杂的协议,您应该了解HTTP规范,请参阅即将过时的RFC2616

最好的办法是设置在receiveDataOnSocket的do-while循环条件()改为(与BytesReceived> 0)。它只会在服务器发送响应后关闭连接时起作用。

如果使用持续连接,那么您可以做的下一件最好的事情是使用非阻塞套接字(至少用于接受来自客户端和服务器的数据)并且在数据到达时将它们转发到另一端。它可能工作,但也可能失败。

接下来的事情就是实际执行HTTP,这是C++教程太复杂。

+0

我把bytesReceived == bufferLength放到了我所期望的位置,如果有更多的数据,缓冲区总是会填充,那么如果我的缓冲区少了,我知道我拥有了所有的东西,并且可以从循环中断开。如果我只是说bytesReceived> 0,它会返回recv方法并挂起等待更多的数据时,如果没有任何,所以我怎么能轮到 – Boardy

+0

谢谢我会研究,没有意识到HTTP是任何比从套接字读出并直接夹持到另一个套接字更复杂。 – Boardy

+0

从我所看到的,我在做什么应该可以工作,只需接收来自一个套接字的数据并夹紧到另一个套接字,这也是通过代码来验证的,所以我显然增加了延迟,然后我从转发到设备获得完整的响应。我已经做了一个测试,在recv函数前放置了10ms的睡眠时间,现在它工作得很好。 – Boardy

相关问题