Added raw send and receive. Fixed TcpSocket close bug.
Can now send and receive raw data over TcpSockets for communicating with other protocols, such as HTTP. Fixed TcpSocket::close only calling close() if the connection isn't open (gg wp)
This commit is contained in:
parent
a9493fca2a
commit
a3eb2ccd0a
@ -67,15 +67,45 @@ public:
|
||||
return is_connected;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Attempts to send raw data down the socket, without
|
||||
* any of frnetlib's framing. Useful for communicating through
|
||||
* different protocols.
|
||||
*
|
||||
* @param data The data to send.
|
||||
* @param size The number of bytes, from data to send. Be careful not to overflow.
|
||||
* @return The status of the operation.
|
||||
*/
|
||||
Status send_raw(const char *data, size_t size);
|
||||
|
||||
|
||||
/*!
|
||||
* Receives raw data from the socket, without any of
|
||||
* frnetlib's framing. Useful for communicating through
|
||||
* different protocols. This will attempt to read 'data_size'
|
||||
* bytes, but might not succeed. It'll return how many bytes were actually
|
||||
* read in 'received'.
|
||||
*
|
||||
* @param data Where to store the received data.
|
||||
* @param data_size The number of bytes to try and receive. Be sure that it's not larger than data.
|
||||
* @param received Will be filled with the number of bytes actually received, might be less than you requested.
|
||||
* @return The status of the operation, if the socket has disconnected etc.
|
||||
*/
|
||||
Status receive_raw(void *data, size_t data_size, size_t &received);
|
||||
|
||||
private:
|
||||
/*!
|
||||
* Reads size bytes into dest from the socket.
|
||||
* Unlike receive_raw, this will keep trying
|
||||
* to receive data until 'size' bytes have been
|
||||
* read, or the client has disconnected/there was
|
||||
* an error.
|
||||
*
|
||||
* @param dest Where to read the data into
|
||||
* @param size The number of bytes to read
|
||||
* @return Operation status.
|
||||
*/
|
||||
Status read_recv(void *dest, size_t size);
|
||||
Status receive_all(void *dest, size_t size);
|
||||
|
||||
std::string unprocessed_buffer;
|
||||
std::unique_ptr<char[]> recv_buffer;
|
||||
|
||||
43
main.cpp
43
main.cpp
@ -41,13 +41,18 @@ void server()
|
||||
{
|
||||
if(selector.is_ready(**iter))
|
||||
{
|
||||
fr::Packet packet;
|
||||
if((*iter)->receive(packet) == fr::Socket::Success)
|
||||
std::string message(1024, '\0');
|
||||
size_t received;
|
||||
if((*iter)->receive_raw(&message[0], 1024, received) == fr::Socket::Success)
|
||||
{
|
||||
std::string message;
|
||||
packet >> message;
|
||||
std::cout << (*iter)->get_remote_address() << " sent: " << message << std::endl;
|
||||
iter++;
|
||||
|
||||
std::cout << (*iter)->get_remote_address() << " sent: " << message.substr(0, received) << std::endl;
|
||||
|
||||
message.clear();
|
||||
message = "HTTP/1.1 " + std::to_string(200) + " \r\nConnection: close\r\nContent-type: text/html\r\n\r\n<h1>Hey</h1>\r\n";
|
||||
(*iter)->send_raw(&message[0], message.size());
|
||||
std::cout << "Sent" << std::endl;
|
||||
(*iter)->close();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -67,19 +72,19 @@ void server()
|
||||
|
||||
void client()
|
||||
{
|
||||
fr::TcpSocket socket;
|
||||
socket.connect("127.0.0.1", "8081");
|
||||
|
||||
fr::TcpSocket socket2;
|
||||
socket2.connect("127.0.0.1", "8081");
|
||||
|
||||
fr::Packet packet;
|
||||
packet << "Hello, World! - From socket 1";
|
||||
socket.send(packet);
|
||||
|
||||
packet.clear();
|
||||
packet << "Hello, world! - From socket 2";
|
||||
socket2.send(packet);
|
||||
// fr::TcpSocket socket;
|
||||
// socket.connect("127.0.0.1", "8081");
|
||||
//
|
||||
// fr::TcpSocket socket2;
|
||||
// socket2.connect("127.0.0.1", "8081");
|
||||
//
|
||||
// fr::Packet packet;
|
||||
// packet << "Hello, World! - From socket 1";
|
||||
// socket.send(packet);
|
||||
//
|
||||
// packet.clear();
|
||||
// packet << "Hello, world! - From socket 2";
|
||||
// socket2.send(packet);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
@ -23,7 +23,6 @@ namespace fr
|
||||
Socket::Status TcpSocket::send(const Packet &packet)
|
||||
{
|
||||
//Get packet data
|
||||
size_t sent = 0;
|
||||
std::string data = packet.get_buffer();
|
||||
|
||||
//Prepend packet length
|
||||
@ -32,9 +31,15 @@ namespace fr
|
||||
memcpy(&data[0], &length, sizeof(uint32_t));
|
||||
|
||||
//Send it
|
||||
while(sent < packet.get_buffer().size())
|
||||
return send_raw(data.c_str(), data.size());
|
||||
}
|
||||
|
||||
Socket::Status TcpSocket::send_raw(const char *data, size_t size)
|
||||
{
|
||||
ssize_t status = ::send(socket_descriptor, data.c_str() + sent, data.size() - sent, 0);
|
||||
size_t sent = 0;
|
||||
while(sent < size)
|
||||
{
|
||||
ssize_t status = ::send(socket_descriptor, data + sent, size - sent, 0);
|
||||
if(status > 0)
|
||||
{
|
||||
sent += status;
|
||||
@ -52,7 +57,6 @@ namespace fr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Socket::Status::Success;
|
||||
}
|
||||
|
||||
@ -62,14 +66,14 @@ namespace fr
|
||||
|
||||
//Try to read packet length
|
||||
uint32_t packet_length = 0;
|
||||
status = read_recv(&packet_length, sizeof(packet_length));
|
||||
status = receive_all(&packet_length, sizeof(packet_length));
|
||||
if(status != Socket::Status::Success)
|
||||
return status;
|
||||
packet_length = ntohl(packet_length);
|
||||
|
||||
//Now we've got the length, read the rest of the data in
|
||||
std::string data(packet_length, 'c');
|
||||
status = read_recv(&data[0], packet_length);
|
||||
status = receive_all(&data[0], packet_length);
|
||||
if(status != Socket::Status::Success)
|
||||
return status;
|
||||
|
||||
@ -81,17 +85,32 @@ namespace fr
|
||||
|
||||
void TcpSocket::close()
|
||||
{
|
||||
if(!is_connected)
|
||||
if(is_connected)
|
||||
{
|
||||
::close(socket_descriptor);
|
||||
is_connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
Socket::Status TcpSocket::read_recv(void *dest, size_t size)
|
||||
Socket::Status TcpSocket::receive_all(void *dest, size_t size)
|
||||
{
|
||||
//Keep calling recv until there's enough data in the buffer if needed
|
||||
while(unprocessed_buffer.size() < size)
|
||||
size_t bytes_read = 0;
|
||||
while(bytes_read < size)
|
||||
{
|
||||
size_t read = 0;
|
||||
Socket::Status status = receive_raw((uintptr_t*)dest + bytes_read, size, read);
|
||||
if(status == Socket::Status::Success)
|
||||
bytes_read += read;
|
||||
else
|
||||
return status;
|
||||
}
|
||||
return Socket::Status::Success;
|
||||
}
|
||||
|
||||
Socket::Status TcpSocket::receive_raw(void *data, size_t data_size, size_t &received)
|
||||
{
|
||||
received = 0;
|
||||
if(unprocessed_buffer.size() < data_size)
|
||||
{
|
||||
//Read RECV_CHUNK_SIZE bytes into the recv buffer
|
||||
ssize_t status = ::recv(socket_descriptor, recv_buffer.get(), RECV_CHUNK_SIZE, 0);
|
||||
@ -99,6 +118,7 @@ namespace fr
|
||||
if(status > 0)
|
||||
{
|
||||
unprocessed_buffer += {recv_buffer.get(), (size_t)status};
|
||||
received += status;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -112,14 +132,22 @@ namespace fr
|
||||
return Socket::Status::Disconnected;
|
||||
}
|
||||
}
|
||||
|
||||
if(received > data_size)
|
||||
received = data_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
received = data_size;
|
||||
}
|
||||
|
||||
//Copy data to where it needs to go
|
||||
memcpy(dest, &unprocessed_buffer[0], size);
|
||||
unprocessed_buffer.erase(0, size);
|
||||
memcpy(data, &unprocessed_buffer[0], received);
|
||||
unprocessed_buffer.erase(0, received);
|
||||
return Socket::Status::Success;
|
||||
}
|
||||
|
||||
|
||||
void TcpSocket::set_descriptor(int descriptor)
|
||||
{
|
||||
socket_descriptor = descriptor;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user