46std::string current_timestamp() {
47 auto now = std::chrono::system_clock::now();
48 auto time_t_now = std::chrono::system_clock::to_time_t(now);
49 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
50 now.time_since_epoch()) % 1000;
52 std::ostringstream oss;
53 oss << std::put_time(std::localtime(&time_t_now),
"%H:%M:%S");
54 oss <<
'.' << std::setfill(
'0') << std::setw(3) << ms.count();
60int main(
int argc,
char* argv[]) {
76 std::cout <<
"DICOM servers use these key parameters:\n";
77 std::cout <<
" - AE Title: Application Entity identifier (like hostname)\n";
78 std::cout <<
" - Port: TCP listening port\n";
79 std::cout <<
" - Max PDU: Maximum data unit size per transfer\n";
80 std::cout <<
" - Timeouts: Connection and idle timeouts\n\n";
83 uint16_t port = 11112;
86 int port_arg = std::stoi(argv[1]);
87 if (port_arg > 0 && port_arg < 65536) {
88 port =
static_cast<uint16_t
>(port_arg);
90 }
catch (
const std::exception&) {
110 {
"Port", std::to_string(config.
port)},
112 {
"Idle Timeout", std::to_string(config.
idle_timeout.count()) +
" seconds"},
113 {
"Max PDU Size", std::to_string(config.
max_pdu_size) +
" bytes"}
133 std::cout <<
"DICOM Service Class Provider (SCP) types:\n";
134 std::cout <<
" - Verification SCP: C-ECHO (connectivity test)\n";
135 std::cout <<
" - Storage SCP: C-STORE (receive images)\n";
136 std::cout <<
" - Query SCP: C-FIND (search data)\n";
137 std::cout <<
" - Retrieve SCP: C-GET/C-MOVE (retrieve data)\n\n";
140 auto server = std::make_unique<net::dicom_server>(config);
145 auto verification_service = std::make_shared<svc::verification_scp>();
146 server->register_service(verification_service);
148 std::cout <<
"Registered services:\n";
149 for (
const auto& sop_class : server->supported_sop_classes()) {
150 if (sop_class ==
"1.2.840.10008.1.1") {
151 std::cout <<
" - Verification SCP (1.2.840.10008.1.1)\n";
153 std::cout <<
" - " << sop_class <<
"\n";
173 std::cout <<
"DICOM Association lifecycle:\n";
174 std::cout <<
" 1. A-ASSOCIATE-RQ -> Client requests connection\n";
175 std::cout <<
" 2. A-ASSOCIATE-AC -> Server accepts\n";
176 std::cout <<
" 3. DIMSE exchange -> C-ECHO, C-STORE, etc.\n";
177 std::cout <<
" 4. A-RELEASE -> Clean disconnection\n\n";
180 std::atomic<int> connection_count{0};
181 std::atomic<int> total_connections{0};
185 server->on_association_established(
189 std::cout <<
"[" << current_timestamp() <<
"] "
193 <<
" (active: " << connection_count <<
")\n";
199 server->on_association_released(
202 std::cout <<
"[" << current_timestamp() <<
"] "
206 <<
" (active: " << connection_count <<
")\n";
213 [](
const std::string& error_msg) {
214 std::cerr <<
"[" << current_timestamp() <<
"] "
217 << error_msg <<
"\n";
236 <<
"Shutdown signal received..."
242 auto start_result = server->start();
243 if (start_result.is_err()) {
245 start_result.error().message);
251 "Echo Server Running",
254 " echoscu -aec ECHO_SCP localhost " + std::to_string(config.
port),
256 "Test multiple connections:",
257 " for i in {1..5}; do echoscu -aec ECHO_SCP localhost " +
258 std::to_string(config.
port) +
"; done",
260 "Press Ctrl+C to stop"
275 auto stats = server->get_statistics();
278 {
"Total Associations", std::to_string(stats.total_associations)},
279 {
"Rejected Associations", std::to_string(stats.rejected_associations)},
280 {
"Messages Processed", std::to_string(stats.messages_processed)},
281 {
"Bytes Received", std::to_string(stats.bytes_received)},
282 {
"Bytes Sent", std::to_string(stats.bytes_sent)},
283 {
"Uptime", std::to_string(stats.uptime().count()) +
" seconds"}
288 "Congratulations! You have learned:",
290 "1. Server Configuration - AE Title, port, timeouts",
291 "2. Service Registration - SCP services for DIMSE handling",
292 "3. Association Lifecycle - Connect, exchange, release",
293 "4. Event Callbacks - Monitoring and logging",
294 "5. Graceful Shutdown - Clean resource cleanup",
296 "Next step: Level 3 - Storage Server (C-STORE SCP)"
DICOM Association management per PS3.8.
DICOM Association management class.
std::string_view calling_ae() const noexcept
Get calling AE title.
std::string_view called_ae() const noexcept
Get called AE title.
void wait()
Block until shutdown signal is received.
Console output utilities for developer samples.
Multi-threaded DICOM server for handling multiple associations.
constexpr const char * reset
Reset all formatting.
constexpr const char * red
constexpr const char * yellow
constexpr const char * green
constexpr const char * cyan
void print_error(std::string_view message)
Print an error message.
void print_table(std::string_view title, const std::vector< std::pair< std::string, std::string > > &rows)
Print a key-value table.
void print_header(std::string_view title)
Print a header/title with decorative border.
void print_success(std::string_view message)
Print a success message.
void print_section(std::string_view title)
Print a section header.
void print_box(const std::vector< std::string > &lines)
Print text in a decorative box.
DICOM Server configuration structures.
Cross-platform signal handling for graceful shutdown.
Configuration for DICOM server.
size_t max_associations
Maximum concurrent associations (0 = unlimited)
std::chrono::seconds idle_timeout
Idle timeout for associations (0 = no timeout)
uint32_t max_pdu_size
Maximum PDU size for data transfer.
std::string implementation_version_name
Implementation Version Name.
uint16_t port
Port to listen on (default: 11112, standard alternate DICOM port)
std::string ae_title
Application Entity Title for this server (16 chars max)
std::string implementation_class_uid
Implementation Class UID.
DICOM Verification SCP service (C-ECHO handler)