전문 통신이란,
먼저 'Fixed Length Format'은 전문을 구성하는 field들의 길이를 입력받을 수 있는 최대 사이즈로 고정시키는 방식입니다.
대규모의 프로젝트를 진행하다 보면 서로 다른 시스템끼리 데이터를 주고받아야 하는 상황이 생깁니다. 이 경우 시스템 간의 통신에서 데이터 송수신 format을 정하는 것도 중요한데요.
일반적으로 데이터를 송수신하는 전문의 형태는 JSON, XML, Fixed Length 등 여러 가지로 구성할 수 있습니다.
(요즘은 XML, JSON 등의 format 형태가 많이 사용되지만 C언어와의 통신에서는 데이터 송수신 format으로 C언어에서 사용하기 편리한 형태인 Fixed Length 형태도 많이 사용됩니다.)
전문은 일정한 크기의 공통된 데이터를 가진 header 부분과 실제 해당 통신에 필요한 데이터를 가진 body 부분, 이렇게 크게 두 가지로 나눠집니다. 그리고 전문을 구성하는 데이터 type에서 int, long 등과 같은 데이터는 이기종 시스템 간의 endian 문제가 발생할 수 있기 때문에 모두 char로만 구성하는 것이 좋습니다.
* endian 엔디언은 숫자를 구성하는 바이트를 컴퓨터가 정렬하는 방식입니다.
전문 통신의 데이터 예
예를 들어서 전문 통신에서 요청 전문으로 "이름", "전화번호"를 보내면 필요한 데이터를 응답 전문으로 보내주는 통신이 있다고 할 때 "이름"은 고정된 사이즈가 20자리(20byte), "전화번호"는 고정된 자리가 11자리(11byte)라고 할 때, 보내야 하는 요청 전문의 예시는 다음과 같습니다.
(정의된 요구사항에 따라 좌측 정렬, 우측 정렬이 변경될 수 있습니다.)
아무개 01012345678
이러한 형태가 나오는 이유는 Fixed Length Format의 특성상 고정된 사이즈에 맞게 데이터를 보내야 하기 때문입니다.
"아무개"라는 문자열은 9byte로 20byte보다 11byte만큼 작습니다. 때문에 해당 문자열 뒤에 ' '공백이 11byte 더 붙어야 이름에 해당하는 데이터 값을 지정된 20byte에 맞출 수 있게 됩니다.
***
UTF-8로 인코딩 된 한글은 한 글자에 3byte의 공간을 차지합니다. 만약 EUC-KR과 같은 인코딩 방식을 사용한다면 한글은 한 글자에 2byte의 공간을 차지하게 됩니다.
전문 통신에 사용할 문자열 길이를 맞추는 메서드
아래는 전문 통신에 사용할 문자열의 길이를 맞추는 메서드입니다. 정렬 기준과 인코딩(UTF-8, EUC-KR)에 따라서 나눠져 있습니다.
***
String은 불변(Immutable)의 성질을 가지고 있습니다. 따라서 문자열을 자주 더해야 하는 경우 String이 아닌 StringBuilder, StringBuffer를 사용합니다.
(String과 StringBuilder, StringBuffer에 대한 자세한 내용은 맨 아래 '함께 보면 좋은 글' 부분에 링크를 첨부해놓겠습니다.)
// 좌측 정렬 / 인코딩 UTF-8
public String fillLengthUTF8Left(int length, String str, boolean fillZero) {
StringBuffer padded = new StringBuffer(str);
while (padded.toString().getBytes(StandardCharsets.UTF_8).length < length) {
if (fillZero) {
padded.append('0');
} else {
padded.append(' ');
}
}
return padded.toString();
}
// 좌측 정렬 / 인코딩 EUC-KR
public String fillLengthEUCKRLeft(int length, String str, boolean fillZero) throws UnsupportedEncodingException {
StringBuffer padded = new StringBuffer(str);
while (padded.toString().getBytes("EUC_KR").length < length) {
if (fillZero) {
padded.append('0');
} else {
padded.append(' ');
}
}
return padded.toString();
}
메서드는 인자로 해당 데이터의 고정된 길이 length와 문자열 str, 그리고 fillZero는 빈칸에 채워야 할 값을 ' ' 공백으로 채울 것인지 '0'으로 채울 것인지 여부를 받습니다.
그리고 입력된 문자열의 byte값과 고정된 길이를 비교하여 그 차이만큼 while문을 통해 ' ' 공백 또는 '0'의 값을 오른쪽으로 채우는 방식입니다.
// 우측 정렬 / 인코딩 UTF-8
public String fillLengthUTF8Right(int length, String str, boolean fillZero) {
StringBuffer padded = new StringBuffer();
while (padded.length() < length - str.getBytes(StandardCharsets.UTF_8).length) {
if (fillZero) {
padded.append('0');
} else {
padded.append(' ');
}
}
padded.append(str);
return padded.toString();
}
// 우측 정렬 / 인코딩 EUC-KR
public String fillLengthEUCKRRight(int length, String str, boolean fillZero) throws UnsupportedEncodingException {
StringBuffer padded = new StringBuffer();
while (padded.length() < length - str.getBytes("EUC_KR").length) {
if (fillZero) {
padded.append('0');
} else {
padded.append(' ');
}
}
padded.append(str);
return padded.toString();
}
우측 정렬은 방식이 조금 다릅니다. 고정된 길이와 입력된 문자열의 byte 크기를 계산하여 그 차이만큼의 ' ' 공백 또는 '0'을 채우고 그 뒤에 입력받은 문자열을 붙이는 방식입니다.
String result1 = fillLengthUTF8Right(20, str, false);
System.out.println("[" + result1 + "]");
// [ 아무개]
String result2 = fillLengthEUCKRRight(20, str, false);
System.out.println("[" + result2 + "]");
// [ 아무개]
String result3 = fillLengthUTF8Left(20, str, false);
System.out.println("[" + result3 + "]");
// [아무개 ]
String result4 = fillLengthEUCKRLeft(20, str, false);
System.out.println("[" + result4 + "]");
// [아무개 ]
각 메서드를 실행했을 때의 결과는 다음과 같습니다.
< 함께 보면 좋은 글 >
< 참고 자료 >
'Programming > Java' 카테고리의 다른 글
자바 소켓 통신(Socket)을 사용하는 이유와 동작 원리 및 코드 (2) | 2022.01.25 |
---|---|
LocalDateTime toString() 메서드 사용 시 주의해야 할 점(00초 사라짐) (0) | 2022.01.20 |
Java 대출 이자 계산기 구현하기 (원금균등, 원리금균등, 만기일시) (0) | 2022.01.13 |
Java 날짜와 문자열 LocalDateTime, String 변환하기 (0) | 2022.01.08 |
자바 추상 클래스와 인터페이스의 차이점 이해하기 (2) | 2022.01.06 |