使用C++将流量转发到另一个设备

Forwarding traffic to another device using C++

本文关键字:另一个 转发 C++ 流量 使用      更新时间:2023-10-16

我正在为飞利浦Hue试用一个小项目,同时学习c++。我想做的是充当客户和网桥之间的代理。对于任何客户端来说,该应用程序都是一个桥接器,接收请求并将其传递给桥接器。

我有一个奇怪的问题,如果应用程序正常运行,我只会得到HTTP 200 OK响应,其他什么都没有,如果我遍历代码,我会得到完整的响应。

下面是我的代码,没有线程,没有类,都是在main方法中完成的。

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] = ''; //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());
}
}

发送方法如下:

int WindowsSocket::sendToSocket(SOCKET *clientSocket, string dataToSend)
{
//dataToSend.append("rn");
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个字节的HTTP200OK,但当我断点并逐步执行代码时,我得到了600多个字节,并收到了我所期望的一切。

我不知道问题出在哪里,我一直在睡觉,希望这能"解决"问题,但即使是睡觉也没有什么区别。

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

您最好将receiveDataOnSocket()的do-while循环中的条件设置为while(bytesReceived>0)。只有当服务器在发送响应后关闭连接时,它才会工作。

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

接下来就是实际实现HTTP,这对于C++教程来说太复杂了。