Bug fixes & updated SocketSelector example.
This commit is contained in:
parent
2aeff56569
commit
7d3e0fe5c8
100
README.md
100
README.md
@ -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
|
||||
|
||||
//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())
|
||||
{
|
||||
//Iterate over our clients to find which one has sent data
|
||||
for(auto iter = clients.begin(); iter != clients.end();)
|
||||
//Check if it was the selector who sent data
|
||||
if(selector.is_ready(listener))
|
||||
{
|
||||
fr::TcpSocket &socket = **iter;
|
||||
if(selector.is_ready(socket))
|
||||
std::unique_ptr<fr::HttpSocket<fr::TcpSocket>> socket(new fr::HttpSocket<fr::TcpSocket>);
|
||||
if(listener.accept(*socket) == fr::Socket::Success)
|
||||
{
|
||||
fr::Packet packet;
|
||||
if(socket.receive(packet) == 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))
|
||||
{
|
||||
//Do something with packet
|
||||
//...
|
||||
|
||||
iter++;
|
||||
//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.
|
||||
|
||||
|
||||
@ -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;}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
49
main.cpp
49
main.cpp
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -143,7 +143,6 @@ namespace fr
|
||||
freeaddrinfo(info);
|
||||
|
||||
is_connected = true;
|
||||
|
||||
return Socket::Status::Success;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user