183 lines
4.8 KiB
Markdown
183 lines
4.8 KiB
Markdown
# Sockeye
|
|
|
|
An easy-to-use, fast, and robust C++ epoll socket library.
|
|
|
|
## API Reference
|
|
|
|
### sockeye::Socket
|
|
|
|
Main server class for handling TCP connections.
|
|
|
|
#### Constructor
|
|
|
|
```cpp
|
|
explicit Socket(uint16_t port = 8080, int timeout_ms = 5000)
|
|
```
|
|
|
|
Constructs a server instance. `timeout_ms` is the duration of inactivity in milliseconds before a client connection is automatically closed.
|
|
|
|
#### Methods
|
|
|
|
**`bool start()`**
|
|
Initialize the server socket and event system. Returns `true` on success.
|
|
|
|
**`void run()`**
|
|
Start the event loop. This is a blocking call that runs until `stop()` is called.
|
|
|
|
**`void stop()`**
|
|
Stops the server and causes the `run()` loop to exit.
|
|
|
|
**`bool send(int client_fd, const std::string& data)`**
|
|
Sends data to a connected client. This method handles partial sends and ensures all data is written. Returns `true` on success.
|
|
|
|
**`void on_connection(ConnectionHandler handler)`**
|
|
Set a callback to be executed when a new client connects.
|
|
|
|
**`void on_data(DataHandler handler)`**
|
|
Set a callback to be executed when data is received from a client.
|
|
|
|
**`void on_disconnect(DisconnectHandler handler)`**
|
|
Set a callback to be executed when a client disconnects for any reason (including timeout).
|
|
|
|
#### Handler Types
|
|
|
|
```cpp
|
|
using ConnectionHandler = std::function<void(int client_fd)>;
|
|
using DataHandler = std::function<void(int client_fd, const char* data, size_t len)>;
|
|
using DisconnectHandler = std::function<void(int client_fd)>;
|
|
```
|
|
|
|
## Examples
|
|
|
|
### Basic Echo Server
|
|
|
|
This example demonstrates how to echo all received data back to the client. It captures the `server` object to use the integrated `send` method.
|
|
|
|
```cpp
|
|
#include "sockeye.hpp"
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
int main() {
|
|
sockeye::Socket server(8080);
|
|
|
|
server.on_connection([](int client_fd) {
|
|
std::cout << "Client connected: " << client_fd << std::endl;
|
|
});
|
|
|
|
// Capture server to use its send method
|
|
server.on_data([&server](int client_fd, const char* data, size_t len) {
|
|
// Echo data back to client using the server's send method
|
|
server.send(client_fd, std::string(data, len));
|
|
});
|
|
|
|
server.on_disconnect([](int client_fd) {
|
|
std::cout << "Client disconnected: " << client_fd << std::endl;
|
|
});
|
|
|
|
if (!server.start()) {
|
|
std::cerr << "Failed to start server" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
server.run();
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
### HTTP Server with Keep-Alive
|
|
|
|
This example shows a simple HTTP server that properly handles keep-alive connections. The library automatically manages client timeouts.
|
|
|
|
```cpp
|
|
#include "sockeye.hpp"
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <mutex>
|
|
|
|
int main() {
|
|
sockeye::Socket server(8080);
|
|
|
|
// Buffers for accumulating request data per client
|
|
std::unordered_map<int, std::string> request_buffers;
|
|
std::mutex buffer_mutex;
|
|
|
|
server.on_data([&](int client_fd, const char* data, size_t len) {
|
|
std::string request_chunk(data, len);
|
|
|
|
std::lock_guard<std::mutex> lock(buffer_mutex);
|
|
request_buffers[client_fd] += request_chunk;
|
|
|
|
// Check if we have a full HTTP request
|
|
if (request_buffers[client_fd].find("\r\n\r\n") != std::string::npos) {
|
|
std::string response =
|
|
"HTTP/1.1 200 OK\r\n"
|
|
"Content-Length: 13\r\n"
|
|
"Connection: keep-alive\r\n\r\n"
|
|
"Hello, World!";
|
|
|
|
server.send(client_fd, response);
|
|
|
|
// Clear buffer for this client for the next request
|
|
request_buffers[client_fd].clear();
|
|
}
|
|
});
|
|
|
|
server.on_disconnect([&](int client_fd) {
|
|
std::cout << "Client disconnected: " << client_fd << std::endl;
|
|
std::lock_guard<std::mutex> lock(buffer_mutex);
|
|
request_buffers.erase(client_fd);
|
|
});
|
|
|
|
if (!server.start()) {
|
|
std::cerr << "Failed to start server" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
std::cout << "Server listening on port 8080" << std::endl;
|
|
server.run();
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
### Graceful Shutdown
|
|
|
|
This example shows how to catch `SIGINT` (Ctrl+C) and `SIGTERM` signals to shut down the server gracefully.
|
|
|
|
```cpp
|
|
#include "sockeye.hpp"
|
|
#include <signal.h>
|
|
#include <iostream>
|
|
|
|
sockeye::Socket* server_ptr = nullptr;
|
|
|
|
void signal_handler(int signal) {
|
|
if (server_ptr) {
|
|
std::cout << "\nCaught signal " << signal << ", stopping server..." << std::endl;
|
|
server_ptr->stop();
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
sockeye::Socket server(8080);
|
|
server_ptr = &server;
|
|
|
|
signal(SIGINT, signal_handler);
|
|
signal(SIGTERM, signal_handler);
|
|
|
|
// Set up handlers...
|
|
server.on_connection([](int fd){ /* ... */ });
|
|
|
|
if (!server.start()) {
|
|
return 1;
|
|
}
|
|
|
|
std::cout << "Server started. Press Ctrl+C to exit." << std::endl;
|
|
server.run();
|
|
std::cout << "Server stopped." << std::endl;
|
|
|
|
return 0;
|
|
}
|
|
```
|