Handling C-MOVE with a single process

All other questions regarding DCMTK

Moderator: Moderator Team

Post Reply
Message
Author
pgimeno
Posts: 9
Joined: Tue, 2023-02-07, 08:24

Handling C-MOVE with a single process

#1 Post by pgimeno »

Hello, new user here.

In my application I need to process images by retrieving them from a PACS server, and for that purpose I need to use a C-FIND to find the images, and then a C-MOVE to the same machine to retrieve them.

For performing the C-MOVE request I'm using a DcmSCU object, similar to the example in https://support.dcmtk.org/redmine/proje ... wto_DcmSCU; however, as the link specifies, "a separate Storage SCP like storescp is needed which actually receives the study images".

But when I tried to add a DcmStorageSCP object for the reception, I faced a chicken-and-egg situation: DcmSCU's sendMOVERequest() sends the request and it doesn't return until the PACS has attempted to establish communication with the destination SCP (which would also be my application). Similarly, the listen() method in DcmSCP either blocks indefinitely, or blocks until the specified timeout has passed and then shuts down the listening socket before returning, Since both calls are blocking, I'm unable to do what I need, which is to start listening, send the request, handle the transfer, handle the response to the request and stop listening.

I've moved the DcmStorageSCP object's listen call to a separate thread, and that works, but it has reliability problems. It looks like the DcmStorageSCP class is designed for a limited range of applications that doesn't include this kind of usage.

So I wanted to ask:

1. How would I go about implementing a system that is able to start listening only just before requesting a C-MOVE, making sure it is actually listening first, and stop listening when the transfer has either succeeded, failed or timed out?
2. Is it possible to satisfy the requirements in question 1 using the same thread for both SCU and SCP?

I'm using version 3.6.5 if that matters.

Michael Onken
DCMTK Developer
Posts: 2048
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

Re: Handling C-MOVE with a single process

#2 Post by Michael Onken »

Hi,

using DcmSCU/DcmSCP it is not possible to implement the desired scenario in a single process. Instead, you have to use two threads or two separate processes.

With DCMTK, however, it is possible to do this in a single process if you use the C API directly. See dcmnet/apps/movescu.cc (the movescu tool) as an example. It internally uses the C method DIMSE_moveUser() from dcmnet/libsrc/dimmove.cc which allows you to provide callback functions to handle incoming storage messages. DcmSCU uses a non-MOVE-specific C method (DIMSE_sendMessageUsingMemoryData() from dcmnet/libsrc/dimse.cc) instead that does not specify such "sub operation" (=storage) callbacks.

It would be possible to also add a DIMSE_moveUser()-based C-MOVE method to DcmSCU but this is not planned yet (we are open to patches and/or sponsorings, though :wink: ).

Best regards,
Michael

pgimeno
Posts: 9
Joined: Tue, 2023-02-07, 08:24

Re: Handling C-MOVE with a single process

#3 Post by pgimeno »

Thanks Michael. You say:
Michael Onken wrote: Tue, 2023-02-07, 14:14 using DcmSCU/DcmSCP it is not possible to implement the desired scenario in a single process. Instead, you have to use two threads or two separate processes.
I need to start the SCP right before sending the C-MOVE request and stop it either right after the transmission is completed, or the response reports an error, or the PACS times out.

With the current design of the DcmSCP class, I can't guarantee with either of the methods you mention (process or thread) that the SCP has opened the port and is ready to accept connections. I can attempt a connection from the SCU thread, to verify whether the port is open, but that has its own problems.

The advantage of handling it in a process is that I can kill it to force termination, which is something that I can't do with a thread, so the thread solution has even more problems. And the process solution gets messy because it needs IPC.

Michael Onken wrote: Tue, 2023-02-07, 14:14 With DCMTK, however, it is possible to do this in a single process if you use the C API directly. See dcmnet/apps/movescu.cc (the movescu tool) as an example. It internally uses the C method DIMSE_moveUser() from dcmnet/libsrc/dimmove.cc which allows you to provide callback functions to handle incoming storage messages. DcmSCU uses a non-MOVE-specific C method (DIMSE_sendMessageUsingMemoryData() from dcmnet/libsrc/dimse.cc) instead that does not specify such "sub operation" (=storage) callbacks.
Can I find any documentation on these functions, or do I have to learn about them by studying the code? Is there a simpler example, similar to the DcmSCU one, which handles only the necessary parts for a successful C-MOVE operation to the same process? (if I'm understanding it correctly, a DIMSE_moveUser() simple example?) I have already taken a look at the movescu source and I was daunted.

Michael Onken
DCMTK Developer
Posts: 2048
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

Re: Handling C-MOVE with a single process

#4 Post by Michael Onken »

Hi,

I think starting DcmSCP to listen for incoming objects in one thread, and then starting DcmSCU to issue the C-MOVE request in the other thread, should not be a problem.

Look at dcmnet/tests/tscuscp.cc which uses a DcmSCU and DcmSCP (or, very small derived classes), and starts them in threads to communicate with each other. It only takes a few lines of code. The tests use OFStandard::forceSleep(2) to wait 2 seconds for DcmSCP to actually be online for listening. Alternatively, as you proposed, you could use the DcmSCU thread to send a C-ECHO to it first (which should be super fast), to make sure it is online, if you are *really* scared.

The tscuscp.cc tests run on dozens of platforms on our build server(s) so I expect that the same principle will also work on your target platform.

I agree DIMSE_moveUser() lacks documentation, so the best way is to look at the movescu code to see how it works, sorry :-/ The lack of good documentation on some parts of the network C API in DCMTK and its "complicated use" is one reason I started DcmSCU and DcmSCP many years ago. For this case, I really recommend to use two processes or threads. I have done this in various projects as well and it does the trick.I don't think we will integrate the DIMSE_moveUser() approach in DcmSCU soon unless we have a project that requires it.

Best regards,
Michael

Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 1 guest