Bug fixes & updated SocketSelector example.

This commit is contained in:
Cloaked9000 2016-12-15 15:47:19 +00:00
parent 2aeff56569
commit 7d3e0fe5c8
5 changed files with 58 additions and 98 deletions

106
README.md
View File

@ -163,66 +163,72 @@ You can both set and get GET/POST data through the fr::(HttpRequest/HttpResponse
```c++
#include <SocketSelector.h>
//Bind to port
fr::TcpListener listener;
if(listener.listen("8081") != fr::Socket::Success)
{
std::cout << "Failed to listen to port" << std::endl;
return;
}
//Create a selector and a container for holding connected clients
fr::SocketSelector selector;
std::vector<std::unique_ptr<fr::TcpSocket>> clients;
//Add our connection listener to the selector
selector.add(listener);
//Infinitely loop, waiting for connections or data
while(selector.wait()))
{
//If the listener is ready, that means we've got a new connection
if(selector.is_ready(listener))
//Bind to port
fr::TcpListener listener;
if(listener.listen("8080") != fr::Socket::Success)
{
//Accept the new connection
std::unique_ptr<fr::TcpSocket> new_client = std::unique_ptr<fr::TcpSocket>(new fr::TcpSocket());
if(listener.accept(*new_client) == fr::Socket::Success)
{
//Add them to the selector, and our socket list
selector.add(*new_client);
clients.emplace_back(std::move(new_client));
}
//Error
}
else
{
//Iterate over our clients to find which one has sent data
for(auto iter = clients.begin(); iter != clients.end();)
{
fr::TcpSocket &socket = **iter;
if(selector.is_ready(socket))
{
fr::Packet packet;
if(socket.receive(packet) == fr::Socket::Success)
{
//Do something with packet
//...
iter++;
//Create socket selector and add listener
fr::SocketSelector selector;
selector.add(listener);
//Create vector to store open connections
std::vector<std::unique_ptr<fr::Socket>> connections;
//Infinitely loop. No timeout is specified so it will not return false.
while(selector.wait())
{
//Check if it was the selector who sent data
if(selector.is_ready(listener))
{
std::unique_ptr<fr::HttpSocket<fr::TcpSocket>> socket(new fr::HttpSocket<fr::TcpSocket>);
if(listener.accept(*socket) == fr::Socket::Success)
{
selector.add(*socket);
connections.emplace_back(std::move(socket));
}
}
//Else it must have been one of the clients
else
{
//Find which client send the data
for(auto iter = connections.begin(); iter != connections.end();)
{
//Eww
fr::HttpSocket<fr::TcpSocket> &client = (fr::HttpSocket<fr::TcpSocket>&)**iter;
//Check if it's this client
if(selector.is_ready(client))
{
//It is, so receive their HTTP request
fr::HttpRequest request;
if(client.receive(request) == fr::Socket::Success)
{
//Send back a HTTP response containing 'Hello, World!'
fr::HttpResponse response;
response.set_body("<h1>Hello, World!</h1>");
client.send(response);
//Remove them from the selector and close the connection
selector.remove(client);
client.close();
iter = connections.erase(iter);
}
else
{
iter++;
}
}
else
{
//Client has disconnected. Remove them.
selector.remove(socket);
iter = clients.erase(iter);
iter++;
}
}
else
{
iter++;
}
}
}
}
```
fr::SocketSelector can be used to monitor lots of blocking sockets at once (both fr::TcpSocket's and fr::HttpSocket's), without polling, to see when data is being received or a connection has closed. To add a socket, just call fr::SocketSelector::add, and to remove a socket, which must be done before the socket object is destroyed, call fr::SocketSelector::remove. You can add as many fr::Socket's as you want.It is also important to add your fr::TcpListener to the selector, otherwise you wont be able to accept new connections whilst blocking.

View File

@ -42,6 +42,10 @@ private:
//Stubs
virtual void close(){}
virtual Socket::Status connect(const std::string &address, const std::string &port){return Socket::Error;}
virtual void set_blocking(bool val){}
virtual fr::Socket::Status send_raw(const char*, size_t){return Socket::Error;}
virtual fr::Socket::Status receive_raw(void*, size_t, size_t&){return Socket::Error;}
virtual int32_t get_socket_descriptor() const {return socket_descriptor;}
};
}

View File

@ -11,55 +11,6 @@
int main()
{
fr::SSLListener listener;
if(listener.listen("9091") != fr::Socket::Success)
{
std::cout << "Failed to bind to port" << std::endl;
return 1;
}
while(true)
{
fr::HttpSocket<fr::SSLSocket> http_socket;
if(listener.accept(http_socket) != fr::Socket::Success)
{
std::cout << "Failed to accept client" << std::endl;
continue;
}
fr::HttpRequest request;
if(http_socket.receive(request) != fr::Socket::Success)
{
std::cout << "Failed to receive data" << std::endl;
continue;
}
else
{
std::cout << "Read successfully" << std::endl;
}
std::cout << "Got: " << request.get_body() << std::endl;
fr::HttpResponse response;
response.set_body("<h1>Hello, SSL World!</h1>");
http_socket.send(response);
http_socket.close();
}
// fr::SSLSocket socket;
// if(socket.connect("lloydsenpai.xyz", "443") != fr::Socket::Success)
// return 1;
//
// std::string request = "GET / HTTP/1.1\r\nhost: www.lloydsenpai.xyz\r\n\r\n";
// socket.send_raw(request.c_str(), request.size());
//
// char *data = new char[1024];
// size_t received;
// if(socket.receive_raw(data, 1024, received) != fr::Socket::Success)
// return 2;
//
// std::cout << "Got: " << std::string(data, received) << std::endl;
return 0;
}

View File

@ -37,7 +37,7 @@ namespace fr
if(select_result == 0) //If it's timed out
return false;
else if(select_result == SOCKET_ERROR) //Else if error
throw std::logic_error("select() returned -1");
throw std::logic_error("select() returned -1. Errno: " + std::to_string(errno));
return true;
}

View File

@ -143,7 +143,6 @@ namespace fr
freeaddrinfo(info);
is_connected = true;
return Socket::Status::Success;
}