pythonsocketstcphl7-v2

I cannot send an ack confirmation from my client after receiving an ACK through socket


I have a server that's always listening and waiting for a connection. When a client connect then sends a file to it, it receives it, saves it and then send back an ACK file, my client send back a confirmation that he received the ACK and finally my server close the connection and my client too.

I had an issue while attempting to receive the ACK from my client, but now it's resolved.

BUT, now that I shutdown my socket connection with SHUT_WR (that's telling that we will stop sending after this, if I'm right) I cannot resend my confirmation.

I can't figure out how that's working and how can I:

From my client

  1. Send a file to my server
  2. Receive the ACK from my server
  3. Resend a confirmation

From my server

  1. Receive a file
  2. Send an ACK
  3. Receive the confirmation

I'm stuck. My server is working unless I try to receive or send something.

The following code blocks are my actual files

client.py


import socket
import os
import random
from socket import SHUT_WR

SEPARATOR = "<SEPARATOR>"
BUFFER_SIZE = 8192

HOST = "127.0.0.1"
PORT = 8000

files = ["test1.HL7","test2.HL7","test3.HL7","test4.HL7","test5.HL7","test6.HL7","test7.HL7","test8.HL7"]

fileName = f".\\ClientFiles\\{files[random.randrange(1,8)]}"

filesize = os.path.getsize(fileName)

socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

print(f"[+] Connecting to {HOST}:{PORT}")

socket.connect((HOST, PORT))

print("[+] Connected.")

socket.send(f"{fileName}{SEPARATOR}{filesize}".encode())

# opening file
with open(fileName, "rb") as f:
    print("[*] Reading")
    while True:
        # reading bytes
        bytes_read = f.read(BUFFER_SIZE)
        if not bytes_read:
            # Transmitting is done
            print("[+] File reading is done.")
            break
        # send all the buffer
        socket.sendall(bytes_read)
print(f"[+] File {fileName} sent")

socket.shutdown(SHUT_WR)

print("[*] Waiting for an acknowledgment")

data = socket.recv(BUFFER_SIZE)

print("[+] Acknoledgment recieved")

print(data.decode())

socket.sendall(data.decode().split('|')[9].encode())

print("[+] Acknowledgment confirmation sent")

print("[*] Closing")

socket.close()

server.py

import itertools

import socket

import signal

import ntpath

from pathlib import Path

from consts import *
from helper import *

# Setting Dicionnaries for HL7 ACK Requirements
MSH = {0:'MSH',2:'', 3:'', 4:'', 5:'', 6:'', 7:'', 8:'', 9:'', 10:'', 11:'',12:'', 13:'', 14:'', 15:'NE', 16:'AL', 17:'', 18:'', 19:'', 20:'', 21:''}
MSA = {0:'MSA', 1:'AA', 2:''}
ACK = {'MSH':{}, 'MSA':{}}

def hl7_ack_generator():
    """Generate the Acknowledgement file and sends it to the client

    Returns:
        String: Returns the Acknowledgment filename
    """
    content = ""

    # Switch sender-receiver
    MSH[3], MSH[5], MSH[4], MSH[6] = MSH[5], MSH[3], MSH[6], MSH[4]

    # Set the message type.
    # If possible get the message trigger to return the same trigger
    try:
        MSH[9] = f"ACK^{check_msh_9_trigger_event(MSH[9].decode().split('^'))}^ACK"
    except:
        MSH[9] = "ACK"

    # Set MSH values
    for param in MSH:
        ACK['MSH'][param] = MSH.get(param)
    # Set MSA values
    for param in MSA:
        ACK['MSA'][param] = MSA.get(param)
    # Create the ACK message
    # Handle integers & bytes in each fields
    # Get MSH values
    for i in range(0,21) :
        if i != 1:
            if ACK['MSH'][i]:
                # Generate a message id based on recieved message timestamp and message id 
                # not exceeding 20 chars
                if i == 10:
                    ACK['MSH'][10] = ACK['MSH'][7].decode() + ACK['MSH'][10].decode()
                    if len(ACK['MSH'][10]) > 20:
                        ACK['MSH'][10] = ACK['MSH'][10][:20]
                    content += ACK['MSH'][10]
                else:
                    try:
                        content += ACK['MSH'][i].decode()
                    except:
                        if not ACK['MSH'][i] == None:
                            content += ACK['MSH'][i]
            content += '|'
    content += "\r"
    # Get MSA values
    for i in range(0,3):
        try:
            content += ACK['MSA'][i].decode()
        except:
            if not ACK['MSA'][i] == None:
                content += ACK['MSA'][i]
        content += "|"

    # Create the ACK filename
    filename = ACK['MSH'][10] + "_ACK.HL7"

    # create the ACK file and write its content
    with open(Path(SERVER_ACK_FILES_FOLDER + filename), "w") as f:
        f.write(content)
        f.close()

    return filename

socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# test the binding
try:
    socket.bind((SERVER_HOST, SERVER_PORT))

except socket.error as error:

    print('Bind failed. Error Code : '
          + str(error[0]) + ' Message '
          + error[1])

    exit()

# Handle ctrl+c
def signal_handler(sign, frame):

    print('[*] Shutting down')
    exit(0)

while signal.signal(signal.SIGINT, signal_handler):

    # connection limit(5 connection try then deny)
    socket.listen(5)

    print(f"[*] Listening as {SERVER_HOST}:{SERVER_PORT}")

    # accept the connection if there is any
    client_socket, address = socket.accept()

    # Below code is executed if sender is connected
    print(f"[+] {address} is connected.")

    # get what the client is sending
    received = client_socket.recv(BUFFER_SIZE)

    filename, bytes_read = received.split(SEPARATOR.encode())

    # get the file size
    fileSize = bytes(itertools.takewhile(lambda i: bytes((i,)).isdigit(), bytes_read))
    bytes_read = bytes_read[len(fileSize):]

    #convert to integer
    fileSize = int(fileSize)
    filename = filename.decode()

    # remove absolute path if there is
    filename = ntpath.basename(filename)

    # start receiving the file from the socket and writing to the file stream
    with open(Path(SERVER_FILES_FOLDER + filename), "wb") as f:

        print("[+] File received")

        while True:
            # write to the file the bytes we just received
            f.write(bytes_read)

            # read 1024 bytes from the socket (receive)
            bytes_read = client_socket.recv(BUFFER_SIZE)

            if bytes_read.startswith(b'MSH'):
                messageHeader = bytes_read.partition(b'\r')[0].split(b'|')
                j = 0
                i = 2
                for i in range(2,17):
                    j+=1
                    # Exclude MSH fields(constant and/or unwanted)
                    if i not in (15,16):
                        MSH[i]= messageHeader[j]
                    #Get message ID
                    if i == 10:
                        MSA[2] = messageHeader[j]
                ackFilename = hl7_ack_generator()

            if not bytes_read:
                # file transmitting is done
                print("[+] File transfert is done")
                break

    with open(Path(SERVER_ACK_FILES_FOLDER + ackFilename), "rb") as f:
        while True:
            bytes_read = f.read(BUFFER_SIZE)
            if not bytes_read:
                print("[+] Acknoledgment Sent")
                break
            client_socket.sendall(bytes_read)

    confirmation = client_socket.recv(BUFFER_SIZE)

    print(confirmation)

    print("[+] Confirmation received")

    print("[*] Closing conneciton")

    client_socket.close()

    socket.close

testX.hl7

MSH|^~\&|ADT1|MCM|LABADT|MCM|198808181126|SECURITY|ADT^A04|MSG00001|P|2.4
EVN|A01-|198808181123
PID|||PATID1234^5^M11||JONES^WILLIAM^A^III||19610615|M-||2106-3|1200 N ELM STREET^^GREENSBORO^NC^27401-1020|GL|(919)379-1212|(919)271-3434~(919)277-3114||S||PATID12345001^2^M10|123456789|9-87654^NC
NK1|1|JONES^BARBARA^K|SPO|||||20011105
NK1|1|JONES^MICHAEL^A|FTH
PV1|1|I|2000^2012^01||||004777^LEBAUER^SIDNEY^J.|||SUR||-||1|A0-
AL1|1||^PENICILLIN||PRODUCES HIVES~RASH
AL1|2||^CAT DANDER
DG1|001|I9|1550|MAL NEO LIVER, PRIMARY|19880501103005|F||
PR1|2234|M11|111^CODE151|COMMON PROCEDURES|198809081123
ROL|45^RECORDER^ROLE MASTER LIST|AD|CP|KATE^SMITH^ELLEN|199505011201
GT1|1122|1519|BILL^GATES^A
IN1|001|A357|1234|BCMD|||||132987
IN2|ID1551001|SSN12345678
ROL|45^RECORDER^ROLE MASTER LIST|AD|CP|KATE^ELLEN|199505011201

Thanks for the attention!


Solution

  • I changed my server into this:

    final_size = b''
    
    while True:
        # write to the file the bytes we just received
        f.write(bytes_read)
    
        final_size += bytes_read
                
        if len(final_size) >= fileSize:
            # file transmitting is done
            print("[+] File transfert is done")
            break
    
            # read 1024 bytes from the socket (receive)
            bytes_read = client_socket.recv(BUFFER_SIZE)
    
            if bytes_read.startswith(b'MSH'):
                messageHeader = bytes_read.partition(b'\r')[0].split(b'|')
                j = 0
                i = 2
                for i in range(2,17):
                    j += 1
                    # Exclude MSH fields(constant and/or unwanted)
                    if i not in (15,16):
                        MSH[i]= messageHeader[j]
                        #Get message ID
                        if i == 10:
                            MSA[2] = messageHeader[j]
                    ackFilename = hl7_ack_generator()
    

    And my client to this:

    print(f"[+] File {fileName} sent")
    print("[*] Waiting for an acknowledgment")
    
    data = sock.recv(BUFFER_SIZE)
    
    print("[+] Acknoledgment recieved")
    
    sock.sendall(data.decode().split('|')[9].encode())
    
    print("[+] Acknowledgment confirmation sent")
    
    print("[*] Closing")
    sock.close()