转发流量到另一个设备C++
我正在试飞一个飞利浦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个字节并获得我期待的所有内容。
我看不出有什么问题,我已经把睡在期待这将“修复”的问题,但即使是睡觉没有什么区别。
感谢您提供的任何帮助。
send()/ recv()是低级调用来处理套接字。为了正确处理HTTP,这是一个非常复杂的协议,您应该了解HTTP规范,请参阅即将过时的RFC2616。
最好的办法是设置在receiveDataOnSocket的do-while循环条件()改为(与BytesReceived> 0)。它只会在服务器发送响应后关闭连接时起作用。
如果使用持续连接,那么您可以做的下一件最好的事情是使用非阻塞套接字(至少用于接受来自客户端和服务器的数据)并且在数据到达时将它们转发到另一端。它可能工作,但也可能失败。
接下来的事情就是实际执行HTTP,这是C++教程太复杂。
我把bytesReceived == bufferLength放到了我所期望的位置,如果有更多的数据,缓冲区总是会填充,那么如果我的缓冲区少了,我知道我拥有了所有的东西,并且可以从循环中断开。如果我只是说bytesReceived> 0,它会返回recv方法并挂起等待更多的数据时,如果没有任何,所以我怎么能轮到 – Boardy
谢谢我会研究,没有意识到HTTP是任何比从套接字读出并直接夹持到另一个套接字更复杂。 – Boardy
从我所看到的,我在做什么应该可以工作,只需接收来自一个套接字的数据并夹紧到另一个套接字,这也是通过代码来验证的,所以我显然增加了延迟,然后我从转发到设备获得完整的响应。我已经做了一个测试,在recv函数前放置了10ms的睡眠时间,现在它工作得很好。 – Boardy
你的条件(bytesReceived == this-> bufferLength)是荒谬的 –
阅读更多关于[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/)框架。 –