Wednesday, June 28, 2023

Introduction to DICOM - Chapter 5 – Solving a DICOM Communication Problem

Today we are going to diagnose a communication problem between two DICOM applications and hopefully find the reason for the problem and solve it. I know, we didn’t even start talking about the DICOM network protocol, but hey, we’re not going to read all this 3,000 pages standard together before getting our hands dirty, right?
In this post we'll discuss:
  1. Application Entities (AE’s) – the nodes in the DICOM network and their name – AE Title
  2. Association – a network peer-to-peer session between two DICOM applications
  3. Association Negotiation – The first part of the association in which the two AE’s agree on what can and can’t be done during the Association
  4. The Verification Service using the C-ECHO command – a DICOM Service Class that is used to verify a connection, sort of application level ‘ping’.
  5. The Storage Service using the C-STORE command – a DICOM Service that allows one AE to send a DICOM object to another AE
The C in C-ECHO and C-STORE commands stands for Composite. If you remember, in chapter 4 when discussing the DICOM Data Model, we said that DICOM applications exchange composite objects (the DICOM images that we already know) that are composites of modules from different IE's where IE's are the information entities of the Normalized DICOM data model.

Here's the story:
Complaint 20123

Burt Simpson from Springfield Memorial Hospital reports that he can’t send the screen capture to the PACS. He kept clicking the green “Send” button but he always gets the same error: “Operation Failed!”. The log file Burt copied from the system is attached.
You may ask yourself, what’s the point in analyzing a log of an application that we are never going to use? Well, the truth is that all DICOM logs look alike. Actually, most DICOM applications are quite similar because DICOM software implementations have common ancient ancestors. If it’s a C library it may be the DICOM test node, CTN. If it’s Java than it might be dcm4che. Even if it's PHP or other newer languages, the libraries were transcribed and ported from the old C implementations so all DICOM logs are similar.


The log file in this case, named DICOM-20111207-093017.log, is 250MB long and when you double click it notepad hangs for couple of minutes before crashing. When you open the log using EXCEL you see the same pattern repeating 100 times, one time for every click Burt made, and after isolating one repetition you see this relatively short pattern with exactly four log entries that we’re going to analyze together.

2011-12-1022:22:25.906000  1508   INFO   Association Request Parameteres:
Our Implementation Class UID:    2.16.124.113543.6021.2
Our Implementation Version Name: RZDCX_2_0_1_8
Their Implementation Class UID:   
Their Implementation Version Name:
Application Context Name:    1.2.840.10008.3.1.1.1
Calling Application Name:    RZDCX
Called Application Name:     PACS
Responding Application Name: resp AP Title
Our Max PDU Receive Size: 32768
Their Max PDU Receive Size: 0
Presentation Contexts:
  Context ID:        1 (Proposed)
    Abstract Syntax: =VerificationSOPClass
    Proposed SCP/SCU Role: Default
    Accepted SCP/SCU Role: Default
    Proposed Transfer Syntax(es):
      =LittleEndianExplicit
      =BigEndianExplicit
      =LittleEndianImplicit
  Context ID:        3 (Proposed)
    Abstract Syntax: =SecondaryCaptureImageStorage
    Proposed SCP/SCU Role: Default
    Accepted SCP/SCU Role: Default
    Proposed Transfer Syntax(es):
      =LittleEndianExplicit
Requested Extended Negotiation: none
Accepted Extended Negotiation: none

2011-12-1022:22:26.062000  1508   INFO   Association Request Result: Normal
Association Response Parameteres:
Our Implementation Class UID:    2.16.124.113543.6021.2
Our Implementation Version Name: RZDCX_2_0_1_8
Their Implementation Class UID:    1.2.826.0.1.3680043.2.60.0.1
Their Implementation Version Name: softlink_jdt103
Application Context Name:    1.2.840.10008.3.1.1.1
Calling Application Name:    RZDCX
Called Application Name:     PACS
Responding Application Name: PACS
Our Max PDU Receive Size: 32768
Their Max PDU Receive Size: 32768
Presentation Contexts:
  Context ID:        1 (Accepted)
    Abstract Syntax: =VerificationSOPClass
    Proposed SCP/SCU Role: Default
    Accepted SCP/SCU Role: Default
    Accepted Transfer Syntax: =LittleEndianImplicit
  Context ID:        3 (Abstract Syntax Not Supported)
    Abstract Syntax: =SecondaryCaptureImageStorage
    Proposed SCP/SCU Role: Default
    Accepted SCP/SCU Role: Default
Requested Extended Negotiation: none
Accepted Extended Negotiation: none

2011-12-1022:22:31.234000  1508   INFO   Can't store object because SOP Class was not negotiated or not accepted by peer.  SOP Class UID: 1.2.840.10008.5.1.4.1.1.7, SOP Instance UID: 2.16.124.113543.6021.1.3.3727584845.5056.1323548540.2

2011-12-1022:22:31.234000  1508   ERROR  In DCXREQ, Code: 520, Text: DIMSE No valid Presentation Context ID
Stopped Logging.

The problem is clearly stated in the third log entry and marked as error in the fourth entry. It says that the peer application, the one we want to send our image to refuse to store this type of object. Some toolkits do provide additional helpful information. However, we could have guessed that this will be the problem already  in the second entry of the log in the association request response where the presentation context for secondary captured was marked as not supported by the called AE.

The log above is from the following short C# function that I’ve written for this post:

      public void SendSCImage(DCXOBJ o)
      {
            DCXAPP app = new DCXAPP();
            app.LogLevel = LOG_LEVEL.LOG_LEVEL_INFO;
            app.StartLogging("DICOM.log");
     
            try
            {
                  DCXREQ req = new DCXREQ();
                  req.SendObject("RZDCX", "PACS", "localhost", 6104, o);
            }
            catch (Exception e)
            {
                  MessageBox.Show(e.Message);
            }
           
app.StopLogging();
      }

Together with the function CreateSCImage that we’ve written together in chapter 4 we have this little program that creates a Secondary Image in memory and then attempts sending it:

    DCXOBJ o = CreateSCImage();
    SendSCImage(o);

Before analyzing the log, let’s go over the code of SendSCImage and make sure that we understand it.
The first three lines creates a DCXAPP class, sets the log level to one less than the highest level (which is ‘Debug’). The DCXAPP class is used to control RZDCX’s global settings. Once it goes out of scope, the settings remains.
Then we have the try-catch block that is very straight forward. We create a DCXREQ class and use it to send the object we’ve created using the SendObject method. DCXREQ is a DICOM requester – a DICOM application that initiates DICOM network with another application and sends DICOM commands. SendObject takes five (5) parameters and encapsulates the whole world of DICOM networking in it. All this log was generated by this single method because it does all the work of DICOM networking for you and that’s exactly what’s unique in MODALIZER-SDK, that you don’t have to deal with all these details. Still, it’s good to know what’s inside so when things gets messy you’ll have a clue about what might have gone wrong.
Like all the other networking methods of DCXREQ, the first four (4) parameters of SendObject are used to establish the DICOM network connection with the remote DICOM application.
The first parameter is our Application Entity Title. In the DICOM network every node is an Application Entity (AE) and the node name is AE Title. You might ask why do we need an AE title if we have a server name or IP address and the answer is that an AE Title is sort of alias for the combination of IP address and port number. We can run many DICOM applications on a single server. I can run two instances of my PACS on the same computer, one listening on port 104 which is the standard TCP/IP port reserved for DICOM communication and another one listening on port 1104. Each application can be completely independent of the other. I can run as many DICOM applications as I like all having the same IP address.
BTW, DICOM is almost always used in LAN environment and I strongly discourage anyone from using DICOM in WAN environment though I know some people do this but it’s really not a good idea. DICOM protocol is internal, private, in your local network, preferably in its own dedicated subnet.
AE Titles are case sENsItIVE, 16 characters max.
The second parameter is the AE title of the application that we would like to connect to. We sometime call it the target application or called AE Title or responding AE or simply the peer.
The third parameter is the server name (or IP address) of the server that the called AE runs on.
The fourth parameter is the port number the called AE listens on.
That concludes the parameters that are common to all DCXREQ network methods. With these parameters we can start an ‘Association’ with the called AE.
The new term that’s interesting here is Association. What’s that? That’s like a network session. It’s a frame that the conversation with the called AE is going to take place in.
We can divide the DICOM network communication into two parts. The first part is setting up the Association and the second part is exchanging DICOM commands.
99% of the difficulties in DICOM networking are related the first part – the association negotiation.
Even if this stage passed and we start exchanging commands, the chances are that problems are because of faults in the first part.

The fifth parameter is the object we would like to send.
SendObject does the following:

  1. Start a TCP/IP connection
  2. Negotiates the association parameters to agree what can be done during the association
  3. Send the DICOM object
  4. Close the association
  5. Close the TCP/IP connection

Let’s go back to the log and have a look at the first part of the log now. Here it is:
2011-12-1022:22:25.906000     1508  INFO  Association Request Parameteres:
Our Implementation Class UID:    2.16.124.113543.6021.2
Our Implementation Version Name: RZDCX_2_0_1_8
Their Implementation Class UID:   
Their Implementation Version Name:
Application Context Name:    1.2.840.10008.3.1.1.1
Calling Application Name:    RZDCX
Called Application Name:     PACS
Responding Application Name: resp AP Title
Our Max PDU Receive Size: 32768
Their Max PDU Receive Size: 0

This part of the log is a textual dump of the first information that was sent to the called AE and is called Association Request. It’s a collection of parameters that describe our application, its capabilities and its intentions in this session.
Every log entry in RZDCX log starts with a timestamp, a thread ID (1508 in this case) and the log level of the entry (INFO in this case). In the complete log above I’ve highlighted the timestamps at the beginning of every log entry.
The first element of in the association request identifies our DICOM implementation.

Our Implementation Class UID:    2.16.124.113543.6021.2
Our Implementation Version Name: RZDCX_2_0_1_8

In this case it’s the RZDCX UID and version number. It’s always interesting because DICOM toolkits and systems have their own little glitches so if you know some system has a problem you already identified and you see that you are dealing with the same implementation, you know how to deal with it. It’s also important when communicating with the other application vendor to report the application version.
In the request dump we see only our implementation info but further down the log in the response dump we will see the identification of the called AE.
Then we have the application context name. This is a UID that is reserved for DICOM. It’s always the same.

Application Context Name:    1.2.840.10008.3.1.1.1

Next we have the AE titles: the calling AE title and the called AE title.


Calling Application Name:    RZDCX
Called Application Name:     PACS

Note that this is just the request so it’s the values we passed to SendObject. In the response we will have also what they sent us back. Usually the application that respond to the association request should check that the called AE is matching to its own AE and that the calling AE is something that is found in its configuration file or database. If it doesn’t match, than the called AE can reject the association.
Then we have the Max PDU Size. PDU is an application level ‘packet’ that says how big is the buffer we are willing to consume for each request.

Our Max PDU Receive Size: 32768

In this case we propose no more than 32K. One known problem is that some applications send an association request so big that the called AE can’t consume. We’ll see in a minute why they do that and how to avoid it.
The next chunk of the log is still part of the first entry in the log. The association request includes a list of DICOM services. The items in this list are called presentation contexts:

Presentation Contexts:
  Context ID:        1 (Proposed)
    Abstract Syntax: =VerificationSOPClass
    Proposed SCP/SCU Role: Default
    Accepted SCP/SCU Role: Default
    Proposed Transfer Syntax(es):
      =LittleEndianExplicit
      =BigEndianExplicit
      =LittleEndianImplicit
  Context ID:        3 (Proposed)
    Abstract Syntax: =SecondaryCaptureImageStorage
    Proposed SCP/SCU Role: Default
    Accepted SCP/SCU Role: Default
    Proposed Transfer Syntax(es):
      =LittleEndianExplicit
Requested Extended Negotiation: none
Accepted Extended Negotiation: none

We’ve sent a list with two items. Each item is a presentation context and identifies a DICOM Service that we wish to use during this association. The presentation contexts are oddly numbered. The first is 1, the second is 3 and a third would have been 5. Why? I don’t know. That’s the way it is. As I said, they are oddly numbered.
So the first service we’ve asked for is Verification. It is performed using the DICOM command C-ECHO. In the log we see this:

Abstract Syntax: =VerificationSOPClass

Every service has a UID. In the log file UID’s that are known are replaced by their name. The verification service is a sort of high level ping. It’s a DICOM command called C-ECHO that when sent the peer should respond with a success status. Note that we have not sent a C-ECHO command yet. We just asked the called AE in our association request to use it in the second part. We also didn’t say we will send a C-ECHO. A DICOM application that listens on a port and waits for incoming connections must always implement the verification service. Our little application is not listening on any port yet. At this stage, we only play the client role here and connect to another application. As a client, It’s always a good habit to ask for the verification service. If we don’t ask for it and the application we connect to does not support any of the other services that we ask for than it will hang up on us. By adding the verification to our request we force the server to say yes on at least one thing we ask for.


The second service we’ve asked for is Secondary Capture Image Storage:

Abstract Syntax: =SecondaryCaptureImageStorage


If you remember when we talked about SOP Class UID in chapter 4, I said that SOP is a pair of a service and an object definition. So here we have this combination. We are asking the peer application to store an object that we are going to send and we tell it that the object is going to be a Secondary Capture Image. If we also had another object type, for example a CT Image, than we would have had to ask for a third presentation context for it. The called AE can allow or disallow each one of the services. So it’s possible to create an application that accepts specific types of objects. For example, if we are writing a 3D reconstruction workstation for CT scans we can accept only CT images and thus force the sending application to send us only that type of objects. However, this is not such a good idea because applications tend to send complete studies and there may be in a study images of different classes, for example there may be one series with a CT scan and another one with a report and another one with radiation dose report and if we limit our workstation to accept only CT images than the application that were implemented to send complete studies will keep reporting failures because they can’t send the other objects even though the CT images that we needed has arrived. A better design would be to allow all object types and ignore the ones we don’t need.


This mechanism of negotiating every type of object led some vendors to the very bad habit of simply requesting all the possible objects they know. This can lead to a 50K long association request and if the called AE implementation can read only 32K long requests it can easily crash on the simplest buffer overflow bug. Additionally, sending a 50K association request every time you just want to check a connection by using a C-ECHO command is pure waste of time.


RZDCX’s SendObject negotiates only the required SOP Class UID’s. The DCXREQ Send method sends a set of DICOM files. First it goes over all the files, create a list of all their SOP Classes and then negotiates this list with the called AE.


This concludes our association request. We identified ourselves and stated what we are calling for. Now let’s see what the called AE is going to say. After the association request is sent, the called AE reads the request and sends back an association response. It is almost identical to the request. The called AE simply fills in the form we sent. The second entry in this log is a dump of this response.

2011-12-1022:22:26.062000  1508 INFO Association Request Result: Normal
Association Response Parameteres:
Our Implementation Class UID:    2.16.124.113543.6021.2
Our Implementation Version Name: RZDCX_2_0_1_8
Their Implementation Class UID:    1.2.826.0.1.3680043.2.60.0.1
Their Implementation Version Name: softlink_jdt103
Application Context Name:    1.2.840.10008.3.1.1.1
Calling Application Name:    RZDCX
Called Application Name:     PACS
Responding Application Name: PACS
Our Max PDU Receive Size: 32768
Their Max PDU Receive Size: 32768
Presentation Contexts:
  Context ID:        1 (Accepted)
    Abstract Syntax: =VerificationSOPClass
    Proposed SCP/SCU Role: Default
    Accepted SCP/SCU Role: Default
    Accepted Transfer Syntax: =LittleEndianImplicit
  Context ID:        3 (Abstract Syntax Not Supported)
    Abstract Syntax: =SecondaryCaptureImageStorage
    Proposed SCP/SCU Role: Default
    Accepted SCP/SCU Role: Default
Requested Extended Negotiation: none
Accepted Extended Negotiation: none

From the timestamp you can see that it came back just 1 tenth of a second after the request was sent and that the response status is Normal (I highlighted the parameters that before were empty or has changed). You can also see that now their implementation identification is filled in with the value softlink_jdt103 which identifies a very handy Java utility package from Tiani. Their AE title is indeed “PACS” and they have accepted our association request. There is couple of cases here. One case is that they simply don’t answer. In this case our request will time out without getting any response. Another case is what we have here that is the association request was accepted and we are now connected to the called AE. The third case is that the called AE decides it doesn’t want to talk to us and sends an Association Reject response. For example if its AE title is not “PACS” so it would probably say “Wrong called AE title”. The reason for rejection is encoded in the response status and sometimes has an additional textual explanation.
We also got the list of services back. The verification was accepted but the Secondary Capture Storage was not. This means that if we like we can send a C-ECHO command but we can’t send our Secondary Capture Image using a C-STORE. Because this was what we wanted to do in this association you see the next two log entries:

2011-12-1022:22:31.234000     1508  INFO  Can't store object because SOP Class was not negotiated or not accepted by peer.  SOP Class UID: 1.2.840.10008.5.1.4.1.1.7, SOP Instance UID: 2.16.124.113543.6021.1.3.3727584845.5056.1323548540.2

2011-12-1022:22:31.234000     1508  ERROR In DCXREQ, Code: 520, Text: DIMSE No valid Presentation Context ID
Stopped Logging.

It means that we can’t store the object because the peer doesn’t support this service. Yippy! We actually could figure out what’s wrong ha?! Now Burt can go to the PACS admin and ask him why his PACS can’t store Secondary Captures and the PACS admin is probably going to ask Burt to which server he tried connecting and to what port and then say that port 6104 is the Worklist Manager that serve Modality Worklist and Performed Procedure Step requests (which are DICOM services we’ll learn about later on) and that if we want to send something to the PACS we should try connecting to port 104. Case solved.
OK, let’s run this again and this time connect to port 104. It’s a good idea to have the AE title, IP address and port number of the called AE configurable in our application so we don’t have to compile every time. Most DICOM applications have such configuration. Usually it’s a table with at least the columns: AE Title, host and port and maybe an id and a comment. Here’s the log of a successful sending, this time the log level was set to Debug.

2011-12-1512:22:51.000000  4296   INFO   Association Request Parameteres:
Our Implementation Class UID:    2.16.124.113543.6021.2
Our Implementation Version Name: RZDCX_2_0_1_8
Their Implementation Class UID:   
Their Implementation Version Name:
Application Context Name:    1.2.840.10008.3.1.1.1
Calling Application Name:    RZDCX
Called Application Name:     PACS
Responding Application Name: resp AP Title
Our Max PDU Receive Size: 32768
Their Max PDU Receive Size: 0
Presentation Contexts:
  Context ID:        1 (Proposed)
    Abstract Syntax: =VerificationSOPClass
    Proposed SCP/SCU Role: Default
    Accepted SCP/SCU Role: Default
    Proposed Transfer Syntax(es):
      =LittleEndianExplicit
      =BigEndianExplicit
      =LittleEndianImplicit
  Context ID:        3 (Proposed)
    Abstract Syntax: =SecondaryCaptureImageStorage
    Proposed SCP/SCU Role: Default
    Accepted SCP/SCU Role: Default
    Proposed Transfer Syntax(es):
      =LittleEndianExplicit
Requested Extended Negotiation: none
Accepted Extended Negotiation: none

2011-12-1512:22:51.000000  4296   DEBUG  Constructing Associate RQ PDU
2011-12-1512:22:51.000000  4296   DEBUG  WriteToConnection, length: 310, bytes written: 310, loop no: 1
2011-12-1512:22:51.015000  4296   DEBUG  PDU Type: Associate Accept, PDU Length: 216 + 6 bytes PDU header
  02  00  00  00  00  d8  00  01  00  00  50  41  43  53  20  20
  20  20  20  20  20  20  20  20  20  20  52  5a  44  43  58  20
  20  20  20  20  20  20  20  20  20  20  00  00  00  00  00  00
  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
  00  00  00  00  00  00  00  00  00  00  10  00  00  15  31  2e
  32  2e  38  34  30  2e  31  30  30  30  38  2e  33  2e  31  2e
  31  2e  31  21  00  00  19  01  00  00  00  40  00  00  11  31
  2e  32  2e  38  34  30  2e  31  30  30  30  38  2e  31  2e  32
  21  00  00  1b  03  00  00  00  40  00  00  13  31  2e  32  2e
  38  34  30  2e  31  30  30  30  38  2e  31  2e  32  2e  31  50
  00  00  3b  51  00  00  04  00  00  80  00  52  00  00  1c  31
  2e  32  2e  38  32  36  2e  30  2e  31  2e  33  36  38  30  30
  34  33  2e  32  2e  36  30  2e  30  2e  31  55  00  00  0f  73
  6f  66  74  6c  69  6e  6b  5f  6a  64  74  31  30  33
2011-12-1512:22:51.015000  4296   INFO   Association Request Result: Normal
Association Response Parameteres:
Our Implementation Class UID:    2.16.124.113543.6021.2
Our Implementation Version Name: RZDCX_2_0_1_8
Their Implementation Class UID:    1.2.826.0.1.3680043.2.60.0.1
Their Implementation Version Name: softlink_jdt103
Application Context Name:    1.2.840.10008.3.1.1.1
Calling Application Name:    RZDCX
Called Application Name:     PACS
Responding Application Name: PACS
Our Max PDU Receive Size: 32768
Their Max PDU Receive Size: 32768
Presentation Contexts:
  Context ID:        1 (Accepted)
    Abstract Syntax: =VerificationSOPClass
    Proposed SCP/SCU Role: Default
    Accepted SCP/SCU Role: Default
    Accepted Transfer Syntax: =LittleEndianImplicit
  Context ID:        3 (Accepted)
    Abstract Syntax: =SecondaryCaptureImageStorage
    Proposed SCP/SCU Role: Default
    Accepted SCP/SCU Role: Default
    Accepted Transfer Syntax: =LittleEndianExplicit
Requested Extended Negotiation: none
Accepted Extended Negotiation: none

2011-12-1512:22:51.031000  4296   DEBUG  DIMSE Command To Send:

# Dicom-Data-Set
# Used TransferSyntax: UnknownTransferSyntax
(0000,0000) UL 0                                        #   4, 1 CommandGroupLength
(0000,0002) UI =SecondaryCaptureImageStorage            #  26, 1 AffectedSOPClassUID
(0000,0100) US 1                                        #   2, 1 CommandField
(0000,0110) US 1                                        #   2, 1 MessageID
(0000,0700) US 0                                        #   2, 1 Priority
(0000,0800) US 1                                        #   2, 1 DataSetType
(0000,1000) UI [2.16.124.113543.6021.1.3.3727584845.720.1323944568.6] #  52, 1 AffectedSOPInstanceUID

2011-12-1512:22:51.031000  4296   DEBUG  DIMSE sendDcmDataset: sending 146 bytes
2011-12-1512:22:51.031000  4296   DEBUG  WriteToConnection, length: 12, bytes written: 12, loop no: 1
2011-12-1512:22:51.031000  4296   DEBUG  WriteToConnection, length: 146, bytes written: 146, loop no: 1
2011-12-1512:22:51.031000  4296   DEBUG  DIMSE sendDcmDataset: sending 7894 bytes
2011-12-1512:22:51.031000  4296   DEBUG  WriteToConnection, length: 12, bytes written: 12, loop no: 1
2011-12-1512:22:51.031000  4296   DEBUG  WriteToConnection, length: 7894, bytes written: 7894, loop no: 1
2011-12-1512:22:51.046000  4296   INFO   DIMSE receiveCommand
2011-12-1512:22:51.062000  4296   INFO   DIMSE receiveCommand: 1 pdv's (178 bytes), presID=3
2011-12-1512:22:51.062000  4296   DEBUG  DIMSE Command Received:

# Dicom-Data-Set
# Used TransferSyntax: LittleEndianImplicit
(0000,0002) UI =SecondaryCaptureImageStorage            #  26, 1 AffectedSOPClassUID
(0000,0100) US 32769                                    #   2, 1 CommandField
(0000,0120) US 1                                        #   2, 1 MessageIDBeingRespondedTo
(0000,0800) US 257                                      #   2, 1 DataSetType
(0000,0900) US 45056                                    #   2, 1 Status
(0000,0902) LO [set InstanceNumber to 0]                #  24, 1 ErrorComment
(0000,1000) UI [2.16.124.113543.6021.1.3.3727584845.720.1323944568.6] #  52, 1 AffectedSOPInstanceUID

2011-12-1512:22:51.062000  4296   DEBUG  WriteToConnection, length: 10, bytes written: 10, loop no: 1
Stopped Logging.

The storage command did pass but we got back a warning status (45056 = 0xB000) instead of success (0x0000). We also got a warning comment that the called AE changed Instance Number element from null to 0, maybe in order to index it properly in its database.

We should have talked about transfer syntaxes but this is already a long post so I’ll leave transfer syntaxes for another time.

Let’s summarize what we’ve covered in this post.
  1. The nodes in the DICOM network are called Application Entities (AE) and are identified using a case sensitive name called AE Title.
  2. DICOM communication is always between two AE’s i.e. it is peer-to-peer.
  3. The DICOM ‘session’ is called Association
  4. The association is divided into two stages. The first stage is called Association Negotiation. In the second stage the two AE’s exchange DICOM commands.
  5. In the Association Negotiation, the requesting AE sends a list of presentation contexts that identify DICOM services it wishes to use and the responding AE sends back the same list marked with which services it accepted and can be used and which it declined and can’t be used in this association.
  6. The verification service is an application level service used to verify communication between two AE's
  7. The storage service is used to transfer DICOM objects between AE's. The storage service is negotiated separately for every SOP Class. For example an application can allow storage of CT image and forbid storage of MR images. This is a not a good design though.
That’s it. I hope you still believe me that DICOM is Easy. As always, comments are most welcome.

36 comments:

  1. Excellent articles. Looking forward to next lesson.

    ReplyDelete
  2. Excellent article, Please add articles on MPPS, MWL services

    ReplyDelete
  3. Placing the real-world scenario into the article was brilliant. I can see now after reading this tutorial that I may become the goto DiCom guy at my company, especially if I can speed up our custom viewer which is god awful.

    ReplyDelete
  4. Thank you! The problem with things like dcm4che is that it is horribly undocumented. dcm4che assumes that you know everything about DICOM from reading the 3000 page spec. Thank you for taking the time to define a bunch of these terms.

    ReplyDelete
  5. If DICOM is easy, why would one have to search thru a 250MB log file to find why it failed?

    ReplyDelete
  6. Thanks....your articles helped me a lot about understanding DICOM.

    ReplyDelete
  7. Thanks a lot, you did a good job.

    ReplyDelete
  8. Hi,
    Really a good article,
    but I have a question,
    it s possible to have 2 same AET in the same local network? I mean :
    192.168.1.1 AET: DEVICE1 hostname : ONE
    connected to those AETs:
    192.168.1.2 AET: DEVICE hostname : TWO
    192.168.1.3 AET: DEVICE hostname : THREE

    It s that possible? I mean the DICOM conformance allow that ?

    Thanks in advance !

    ReplyDelete
    Replies
    1. Hi Franz,
      Possible? Yes. Reasonable? No!
      Lets say one of the "DEVICE" (e.g. the one on 192.168.1.2) makes a C-MOVE request from a PACS.
      The PACS reads the Target AE Title parameter and scratch its head: Which "DEVICE" asked this? The one on 192.168.1.2 or the one on 192.168.1.3
      Not a good idea.
      Roni

      Delete
    2. Really thank you for your answer ;)!
      Yeah I understand your answer, but the DICOM standard allows that ? I mean if a modality is DICOM conformed, it's possible...? (personnally I think like you, not a good idea :) )

      Delete
    3. and in your exemple, the AET and the IP adresses are not verified by the PACS? is only the AET verified by the PACS to make the C-MOVE?

      Thanks again ;) !!

      Delete
  9. Hi, Roni!
    I am PACS application speciliast and not so happy with DICOM details. Sometimes setting up DICOM communication with two hosts I see in the logfile messages with related dicom association error codes like 25, 26 etc. How to read them? Do you have a list of defined Dicom-related error codes? Thanks

    ReplyDelete
  10. Excellent articles Roni! I am new to DICOM field and these articles helped me a lot. Thanks for the wonderful work... Regards, Sandhya

    ReplyDelete
  11. Excellent article.
    Your catch line "99% of the difficulties in DICOM networking are related the first part – the association negotiation." helped me not only to resolve most of my issues but also in performance improvement. If one negotiate correct SOP Classes with proper transfer syntaxes, considerable performance improvement will be observed.

    ReplyDelete
  12. Great article, thanks a lot.

    Regards
    Abdelghani Ouchabane

    ReplyDelete
  13. How i will do DICOM ping between Portal server and DICOM device as a technologhy i am using Asp.Net

    ReplyDelete
  14. Great article (same comment as many other) ... :) ... However i am facing a different issue...

    I am using dcm4chee java toolkit to send (using dcmsnd programmatically) a dicom file to a PACS. While i am able to send it to several PACS (dcm4che, Osirix) i am unable when i am trying to send it to some other and i am getting:

    ERROR: Failed to establish association:A-ASSOCIATE-RJ[result=1, source=1, reason=2]: permanent application-context-name-not-supported

    So i am wondering what do i have to do for fixing this issue? What am i missing?

    ReplyDelete
  15. Thx. Application context name not supported is very strange. In DICOM is always the same.Can you share the log of this?

    ReplyDelete
  16. Hi expert, DICOM client can get datas from server. However, when the VPN was enable in the network, connection timeout occurs:
    ERROR: Failed to establish association:
    java.net.SocketTimeoutException: connect timed out

    Network too slow cause timeout?? (confirmed no blacking in the network) Thank you.

    ReplyDelete
  17. When working through VPN this may be related to many issues. Timeout is one, Wrong IP address or wrong port number, all can give the exact same error.
    verify your configuration.

    ReplyDelete
  18. Hi,

    thanks again for the great article. A question about:
    """
    DICOM is almost always used in LAN environment and I strongly discourage anyone from using DICOM in WAN environment though I know some people do this but it’s really not a good idea
    """
    But what if we need to perform a C-store to a DICOM endpoint on a remote network, is VPN robust enough to coop with this? Or do you suggest other protocols?

    thx

    ReplyDelete
    Replies
    1. VPN is good. Secure DICOM (TLS) is also very good. Over WAN there are many alternatives of secure RESTFull API's, WADO and the list is long.
      DICOM Protocol's domain is narrowing to communication with Imaging Devices (Ultrasound, MRI, CT Machines). Once the images are in the PACS the IT system takes over and http based protocols dominate.

      Delete
  19. Hi,

    thanks. Do you have any idea how well DICOM over TLS is supported by the PACS vendors/PACS installed in hosptitals?

    ReplyDelete
  20. I think it will become more popular but I'm not sure how much willing are hospitals to open their PACS directly to the Internet even thro secure DICOM. It's more a solution for a DICOM router.

    ReplyDelete
  21. Please can anyone let me know whether the asynchronous C-MOVE command can be implemented ??

    ReplyDelete
  22. Is there anyway to find out which transfer syntaxes are supported before attempting to send a file?

    For example, I have an AVI file that I want to send to the PACS server. I'd like to send it as MPEG-4 or MPEG-2 to save space but if neither are supported then send it as multi-frame data (PixelData).

    I was thinking it might be possible to construct an object containing a list of valid transfer syntaxes and one invalid one to ensure the association request fails. But there doesn't appear to be a way to access the list of (un)supported presentation contexts.

    ReplyDelete
    Replies
    1. Hi. There is a way. All you need to do is to propose the same sop class once with every transfer syntax and see which of the presentation contexts are accepted. Then use one of the accepted that you prefer. We don't provide this option in rzdcx because it's "low level" so to call it. You can do what you suggest to work around this of course.

      Delete
  23. Hi. Is there an equivalent to RZDCX in Java?

    ReplyDelete
  24. Hey there! I just wanted to ask if you ever have
    any problems with hackers? My last blog (wordpress) was hacked and I
    ended up losing several weeks of hard work due to no data backup.
    Do you have any solutions to protect against hackers?

    ReplyDelete
  25. before your post, I won't believe if someone tell me that DICOM is easy, thank you very much for such a great blog on DICOM. (Now I believe DICOM is complex :P )

    ReplyDelete
  26. Fantastic documents. Thanks a lot

    Wondering why you mentioned that it is a bad idea to use Dicom on a WAN setting. I am working on such a project and any warnings would be amazing to hear.

    ReplyDelete
  27. We are having transmission slowness from our GE CT Modality to our Fuji PACS. This issue has gone on for a full year+. They brought eveyr vendor and tried to fix it. Anyone have any experience with the two? This impacted a critical patient and we need to figure out what is wrong. I just got pulled into this and am thinking it is at the DICOM level maybe or maybe the load balancer.

    Load balancer how ever shows no through put limits being hit. Network utilization never reaches capacity.

    ReplyDelete
    Replies
    1. Hi Sunil,
      You should examine the DICOM log on both sides. On the scanner and on the PACS. Specifically, check the proposed transfer syntax and what was accepted and make sure that your PACS can accept the transfer syntax and the SOP class that the scanner prefers. There may be many reasons for and without collecting more information it will be hard to tell. You can contact me by email and we can discuss further.
      Roni

      Delete