본문 바로가기

Network

소켓 통신 개발자는 쪼잔하다. by 이상민

지난주 회사에 오픈클래스가 열렸다.

강연자는 『자바 성능 튜닝 이야기』, 『자바 개발자와 시스템 운영자를 위한 트러블슈팅 이야기』 등 책을 쓴 이상민 님.

 

강연은 자바, 성능, 도구에 대한 것이 주된 내용이였지만 짧게 "소켓 통신 개발자는 쪼잔하다."라는 말이 나왔다.

 

당시는 그냥 웃고 넘어갔지만, 강연을 마치고 일을 하면서 그 말이 맞음을 느끼게 되었다.

 

1바이트 때문에 삽질

S모 회사와의 포인트 연동을 소켓 통신으로 개발을 하는데 자꾸 closed by peer 에러가 발생하는 것이었다.
내가 전문(payload)을 잘못 만들었나 싶어서 데이터를 확인했는데 계속 발생을 하는 것이다.
결국 wireshark를 이용해서 패킷을 캡쳐해서 보고야 원인을 알 수 있었다.

Payload의 종결자(terminator)로 LF를 쓰고 있는 것으로 명세가 되어 있는데, 서버에서 응답은 LF가 아닌 NUL을 주고 있었던 것이 원인.
결국 1바이트 때문에 클라이언트 프로그램은 데이터가 아직 끝나지 않았다고 판단한 것이고, 서버는 데이터 줄 것을 다주고 FIN, ACK를 하고 있으니 상대방에 의해 끊겼다고 판단하는 것이다.

아스키: 십진수 vs 16진수

전문이 십진수로 되어 있다 보니 자리수가 달라져서 정렬이 되지 않아 가독성이 떨어진다.
16진수라면 2자리로 고정되어 있으므로 정렬이 되어 있을 텐데 말이다.

혼합되어 있는 바이트 데이터

결국 일일이 아스키테이블을 보고 바꾸는 작업을 하고 있는데 든 생각은, 컴퓨터가 적격이지...

아래와 같은 groovy 스크립트를 만들어서 한 방에 해결했다.

def convertToHex(final byte[] data) {
    return new Writable() {
        Writer writeTo(Writer out) throws IOException {
            for (int i = 0; i < data.length; i++) {
                // convert byte into unsigned hex string
                String hexString = Integer.toHexString(data[i] & 0xFF)

                // add leading zero if the length of the string is one
                if (hexString.length() < 2) {
                    out.write("0")
                }

                // write seperator
                if (i > 0) {
                    out.write(", ")
                }

                // write hexa prefix
                out.write("0x")

                // write hex string to writer
                out.write(hexString)
            }
            return out
        }

        String toString() {
            Writer buffer = new StringBuilderWriter()

            try {
                writeTo(buffer)
            } catch (IOException e) {
                throw new StringWriterIOException(e)
            }

            return buffer.toString()
        }
    }
}

def "convertToHex test"() {
    given:
    def original = [0x4e, 66, 98, 0x35, 100, 87, 120, 76, 111, 0x56, 107] as byte[]

    when:
    def result = convertToHex(original)
    println result

    then:
    result.toString() == "0x4e, 0x42, 0x62, 0x35, 0x64, 0x57, 0x78, 0x4c, 0x6f, 0x56, 0x6b"
}