-
Notifications
You must be signed in to change notification settings - Fork 0
TCP and UDP modules
Both TCP and UDP modules allow you to create multiple servers and multiple clients.
They both offer events you can subscribe to. All events from these modules are synchronous.
See the Events wiki for a better understanding of how to subscribe to these events, and how to reinterpret the types of the events' arguments.
See the System wiki.
int main(void) {
fwk::System* framework = new fwk::System();
// initialize the modules you want to use.
framework->initTCP();
framework->initUDP();
framework->run();
delete framework;
}
fwk::TcpManager& tcpManager = fwk::NetworkManager::get().getTCP();
// prepare server
uint16_t port = 4444;
const fwk::TcpServer& server = tcpManager.createServer(port);
// bind and listen
tcpManager.run(server);
The reason why you need to create your server, then run it, is to allow you to subscribe to events before they are fired, which would make you miss information.
All the events subscription below are between the createServer
and run
method calls.
server.events.onAccept->subscribe(
[] (const fwk::IEventArgs* ptr) {
const fwk::TcpSocketStreamEventArgs* args =
reinterpret_cast<const fwk::TcpSocketStreamEventArgs*>(ptr);
// the new client socket
fwk::TcpSocketStream* socket = args->socket;
},
this); // key (see Events wiki)
This example shows how to subscribe to the onReceivedData
event, and how to extract the data received.
Remember that this event, as every other event from this module, is synchronous.
This means that your callback is called directly by the TCP/UDP input thread, so keep operations to a minimum. If you need bigger operations, you can use a fwk::SimpleTask
(see the Tasks wiki).
server.events.onReceivedData->subscribe(
[] (const fwk::IEventArgs* ptr) {
const fwk::TcpSocketStreamEventArgs* args =
reinterpret_cast<const fwk::TcpSocketStreamEventArgs*>(ptr);
// the client who sent the data
fwk::TcpSocketStream* socket = args->socket;
// create a ByteArray in which to extract the received data (if any).
fwk::ByteArray* data = fwk::ByteArray::getFromPool();
// extract the data
socket->extractData(
[] (const fwk::ByteArray& input) -> size_t {
// in this callback, you go through the input ByteArray
// to find the length of the message you are trying to extract
// in this example, we extract the complete buffer
return input.getSize();
},
data);
// the data ByteArray is now filled with the data received on the socket.
// [Use the data]
// Return the ByteArray to its pool if you no longer need it
fwk::ByteArray::returnToPool(data);
},
this); // key (see Events wiki)
server.events.onClientClosed->subscribe(
[] (const fwk::IEventArgs* ptr) {
const fwk::TcpSocketStreamEventArgs* args =
reinterpret_cast<const fwk::TcpSocketStreamEventArgs*>(ptr);
// the client socket which closed
fwk::TcpSocketStream* socket = args->socket;
},
this); // key (see Events wiki)
The fwk::TcpSocket
is the same as the server.server
variable.
server.events.onClosed->subscribe(
[] (const fwk::IEventArgs* ptr) {
const fwk::TcpSocketEventArgs* args =
reinterpret_cast<const fwk::TcpSocketEventArgs*>(ptr);
// the socket which closed
fwk::TcpSocket* socket = args->socket;
},
this); // key (see Events wiki)
fwk::TcpManager& tcpManager = fwk::NetworkManager::get().getTCP();
// prepare client
std::string hostname = "localhost";
uint16_t port = 4444;
const fwk::TcpClient& client = tcpManager.createClient(hostname, port);
// connect
tcpManager.run(client);
See this.
Same as server data received.
client.events.onClosed->subscribe(
[] (const fwk::IEventArgs* ptr) {
const fwk::TcpSocketStreamEventArgs* args =
reinterpret_cast<const fwk::TcpSocketStreamEventArgs*>(ptr);
// the socket which closed
fwk::TcpSocketStream* socket = args->socket;
},
this); // key (see Events wiki)
From any fwk::TcpSocketStream
(gotten from onAccept
or when creating a client), you can add data which will be pushed as soon as possible, asynchronously.
You can also send a fwk::ByteArray
directly.
const char message[] = "foo";
// see above to get the TcpManager
tcpManager.push(
socketStream, // fwk::TcpSocketStream*
message,
strlen(message));
You need to remember that UDP is not a reliable protocol. The events onClosed
or onClientClosed
do not work properly when the "connection" is closed by the other side.
fwk::UdpManager& udpManager = fwk::NetworkManager::get().getUDP();
// prepare server
uint16_t port = 4444;
const fwk::UdpServer& server = udpManager.createServer(port);
// bind
udpManager.run(server);
Remember that events are synchronous.
server.events.onNewClient->subscribe(
[] (const fwk::IEventArgs* ptr) -> void {
const fwk::UdpSocketClientEventArgs* args =
reinterpret_cast<const fwk::UdpSocketClientEventArgs*>(ptr);
// new client
fwk::UdpSocketClient* socket = args->socket;
},
this);
server.events.onReceivedData->subscribe(
[] (const fwk::IEventArgs* ptr) -> void {
const fwk::UdpSocketClientEventArgs* args =
reinterpret_cast<const fwk::UdpSocketClientEventArgs*>(ptr);
// client who sent the data
fwk::UdpSocketClient* socket = args->socket;
// extract the last received datagram
ByteArray* datagram = socket->getData();
if (data != nullptr) {
// use data
}
},
this);
server.events.onClientClosed->subscribe(
[] (const fwk::IEventArgs* ptr) -> void {
const fwk::UdpSocketClientEventArgs* args =
reinterpret_cast<const fwk::UdpSocketClientEventArgs*>(ptr);
// closed client
fwk::UdpSocketClient* socket = args->socket;
},
this);
server.events.onClosed->subscribe(
[] (const fwk::IEventArgs* ptr) -> void {
const fwk::UdpSocketServerEventArgs* args =
reinterpret_cast<const fwk::UdpSocketServerEventArgs*>(ptr);
// closed client
fwk::UdpSocketServer* socket = args->socket;
},
this);
fwk::UdpManager& udpManager = fwk::NetworkManager::get().getUDP();
// prepare client
std::string hostname = "localhost";
uint16_t port = 4444;
const fwk::UdpClient& client =
udpManager.createClient(hostname, port);
// "connect"
udpManager.run(client);
client.events.onReceivedData->subscribe(
[] (const fwk::IEventArgs* ptr) -> void {
const fwk::UdpSocketStreamEventArgs* args =
reinterpret_cast<const fwk::UdpSocketStreamEventArgs*>(ptr);
// get the socket
fwk::UdpSocketStream* socket = args->socket;
// extract the last received datagram
ByteArray* datagram = socket->getData();
if (data != nullptr) {
// use data
}
},
this);
client.events.onClosed->subscribe(
[] (const fwk::IEventArgs* ptr) -> void {
const fwk::UdpSocketStreamEventArgs* args =
reinterpret_cast<const fwk::UdpSocketStreamEventArgs*>(ptr);
// closed socket
fwk::UdpSocketStream* socket = args->socket;
},
this);
From any fwk::UdpSocketStream
(gotten when creating a client) or fwk::UdpSocketClient
(gotten from onNewClient
event), you can push datagrams which will be sent as soon as possible, asynchronously.
You can also send a fwk::ByteArray
directly.
const char message[] = "foo";
fwk::NetworkManager::get().getUDP().push(
socket, // fwk::UdpSocketStream* or fwk::UdpSocketClient*
message,
strlen(message));