๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ“š Kotlin

[TCP Socket ํ†ต์‹ ] Okio ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•œ kotlin socket ํ†ต์‹ 

by GroovyArea 2023. 6. 24.
io stream ๊ณผ socket ์„ ์ด์šฉํ•œ tcp ํ†ต์‹ ์€ java ๋ฅผ ์ฒ˜์Œ ๊ณต๋ถ€ํ•  ๋•Œ, ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ์ฑ„ํŒ… ์ •๋„์˜ ์˜ˆ์ œ๋กœ ์ดํ•ดํ•˜๋ฉฐ ๋„˜์–ด๊ฐ”๋‹ค..
์›ฌ๋งŒํ•œ ํด๋ผ์ด์–ธํŠธ - ์„œ๋ฒ„ ๊ฐ„์˜ ํ†ต์‹ ์€ http ๋กœ ์ด๋ฃจ์–ด์ง€๋ฏ€๋กœ ์ด๋ฅผ ๋” ๊นŠ๊ฒŒ ํŒŒ๋ฉฐ ๊ณต๋ถ€ํ–ˆ์—ˆ๋‹ค.

์ด๋ฒˆ์— ์ด์งํ•œ ํšŒ์‚ฌ์—์„œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ๋งก๊ฒŒ ๋œ ์ฒซ ๊ณผ์ œ๋Š” TCP ์ „๋ฌธ ํ†ต์‹ ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
์†Œ์ผ“ ํ†ต์‹ ์„ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ, java socket api ๋ฅผ ์ด์šฉํ•˜์—ฌ ์ˆœ์ˆ˜ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, kotlin ์—์„œ๋Š” okio ๋ผ๋Š” ํ†ต์‹  ์ „์šฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•ด์„œ ์ด๋ฅผ ํ•œ๋ฒˆ ์‚ฌ์šฉํ•ด์„œ ์ „๋ฌธ ํ†ต์‹ ์„ ์œ„ํ•œ ์†Œ์ผ“ ํด๋ผ์ด์–ธํŠธ ์ดˆ์„์„ ๊ตฌํ˜„ํ•ด๋ดค๋‹ค.

์ž˜ ํ•ด๋ณด์ง€ ์•Š์€ socket ํ†ต์‹ ์„ ์ดํ•ดํ•˜๊ณ  ๊ตฌํ˜„ํ•˜๋ฉฐ ์ดํ‹€๊ฐ„ ๋งŽ์ด ๊ณ ํ†ต ๋ฐ›์•˜๊ณ , ๊ทธ ๊ณผ์ •์—์„œ ์ข€ ๋” ํŽธ๋ฆฌํ•œ kotlin okio ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ„๋‹จํ•˜๊ฒŒ ์†Œ์ผ“ ํ†ต์‹ ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ์˜ˆ์‹œ ์ฝ”๋“œ๋ฅผ ๋ณด์ž.
ํ˜น์‹œ๋‚˜ okio ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ byte ๋ฐฐ์—ด socket ํ†ต์‹ ์„ ํ•˜์‹œ๋ ค๋Š” ๋ถ„๋“ค์—๊ฒŒ ๋„์›€์ด ๋˜๊ธธ ๋ฐ”๋ž€๋‹ค.

 

์ฐธ๊ณ  [Okio ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ]

https://github.com/square/okio

 

GitHub - square/okio: A modern I/O library for Android, Java, and Kotlin Multiplatform.

A modern I/O library for Android, Java, and Kotlin Multiplatform. - GitHub - square/okio: A modern I/O library for Android, Java, and Kotlin Multiplatform.

github.com

https://square.github.io/okio/

 

Okio

Okio Okio is a library that complements java.io and java.nio to make it much easier to access, store, and process your data. It started as a component of OkHttp, the capable HTTP client included in Android. Itโ€™s well-exercised and ready to solve new prob

square.github.io

 

Server ์ฝ”๋“œ

import okio.buffer
import okio.sink
import okio.source
import java.net.ServerSocket
import java.util.concurrent.TimeUnit

fun main() {
    Server().server()
}

class Server {
    fun server() {
        val serverSocket = ServerSocket(9999)
        
        while (true) {
            val client = serverSocket.accept()

            val bufferedSource = client.source().buffer() // ๋‚ด๋ถ€์ ์œผ๋กœ getInputStream() ์„ ํ˜ธ์ถœํ•œ๋‹ค.
            bufferedSource.timeout().timeout(READ_TIME_OUT, TimeUnit.MILLISECONDS)
            val readByteArray = bufferedSource.readByteArray() // byte ๋ฐฐ์—ด๋กœ ์ฝ๊ธฐ
            println(String(readByteArray))

            val bufferedSink = client.sink().buffer() // ๋‚ด๋ถ€์ ์œผ๋กœ getOutputStream() ์„ ํ˜ธ์ถœํ•œ๋‹ค.
            bufferedSink.timeout().timeout(WRITE_TIME_OUT, TimeUnit.MILLISECONDS)
            bufferedSink.write(readByteArray) // ์—์ฝ” ์„œ๋ฒ„ ๋งˆ๋ƒฅ ๋ฐ›์€ byte ๋ฐฐ์—ด์„ ํด๋ผ์ด์–ธํŠธ๋กœ ๋ณด๋‚ด๊ธฐ
            bufferedSink.flush() // flush ๋ฅผ ํ˜ธ์ถœํ•ด์„œ buffer ๋ฅผ ๋น„์šฐ์ž.
            client.shutdownOutput() // eof ๋งˆ๋ƒฅ, write ์ด ๋๋‚ฌ๋‹ค๋Š” ๊ฒƒ์„ socket ์˜ shutdownOutput() ์„ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค.
        }
    }
}
  • ์ž์›์˜ close() ํ•จ์ˆ˜๋ฅผ ๋ช…์‹œํ•˜์ง„ ์•Š์•˜๋‹ค.
    • ์‹ค์ œ ์ฝ”๋“œ์—์„œ๋Š” ํ˜ธ์ถœํ•ด์•ผ.
  • okio ์—์„œ๋Š” input, output stream ๊ฐ™์€ ๊ฒƒ์„ ํ•œ๋ฒˆ ๋ž˜ํ•‘ํ•˜์—ฌ ์ถ”์ƒํ™”ํ–ˆ๋‹ค.
    • source, sink ๋ผ๋Š” ๊ฐ์ฒด๋กœ ์ถ”์ƒํ™”

source : socket ์—์„œ inputstream ๊ฐ€์ ธ์˜ด.
sink : socket ์—์„œ outputstream ๊ฐ€์ ธ์˜ด.

 

Client ์ฝ”๋“œ

import okio.buffer
import okio.sink
import okio.source
import java.io.IOException
import java.net.InetSocketAddress
import java.net.Socket
import java.util.concurrent.TimeUnit

const val SOCKET_CONNECT_TIME_OUT = 5000
const val WRITE_TIME_OUT: Long = 12000
const val READ_TIME_OUT: Long = 12000

fun main() {
    print(
        String(
            requestToTrsServer(
                niceVanIp = "127.0.0.1",
                niceVanPort = 9999,
                buffer = "Hello Server!".toByteArray()
            )
        )
    )
}

fun requestToTrsServer(niceVanIp: String, niceVanPort: Int, buffer: ByteArray): ByteArray {
    Socket().use { socket ->
        try {
            socket.connect(InetSocketAddress(niceVanIp, niceVanPort), SOCKET_CONNECT_TIME_OUT)

            val bufferedSink = socket.sink().buffer()
            with(bufferedSink) {
                timeout().timeout(WRITE_TIME_OUT, TimeUnit.MILLISECONDS)
                write(buffer)
                flush()
                socket.shutdownOutput()
            }
			// ์„œ๋ฒ„๋กœ bytearray ๋ณด๋‚ด๊ธฐ

            val bufferedSource = socket.source().buffer()
            val responseBytes =
                with(bufferedSource) {
                    timeout().timeout(READ_TIME_OUT, TimeUnit.MILLISECONDS)
                    readByteArray()
                }
			// ์„œ๋ฒ„์—์„œ bytearray ๋ฐ›๊ธฐ
            
            bufferedSink.close()
            bufferedSource.close()

            return responseBytes
        } catch (e: IOException) {
            println("์†Œ์ผ“ ์„œ๋ฒ„์™€ TCP ํ†ต์‹  ์ค‘ IOException ๋ฐœ์ƒ")
            return ByteArray(1)
        }
    }
}
  • ํด๋ผ์ด์–ธํŠธ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€
  • bytearray ๋ฅผ ๋ณด๋‚ด๊ณ , ๋ฐ›๋Š” ์ฝ”๋“œ์ด๋‹ค.
  • ์œ„์˜ ๊ฐœ๋…๊ณผ ๋™์ผํ•˜๊ฒŒ, source, sink ๋ฅผ Socket ๊ฐ์ฒด์—์„œ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ์ฝ˜์†”์— ๊ฐ๊ฐ ์ฐํžŒ ๊ฐ’

 

์ด๋ ‡๊ฒŒ, java ์ฝ”๋“œ๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

์†Œ์ผ“ ํ†ต์‹ ์„ ์ œ๋Œ€๋กœ ์ฒ˜์Œ ๊ตฌํ˜„ํ•ด๋ดค๋Š”๋ฐ, ์—ญ์‹œ ๊ณต๋ถ€ํ•  ๊ฑด ๋์ด ์—†๊ณ , ํ•„์š” ์—†๋Š” ๊ฒƒ์€ ์–ด๋””์—๋„ ์—†๋‹ค.

 

"์ด๊ฒƒ๋งŒ ํ•˜๋ฉด ๋˜์ง€~"

๋ผ๋Š” ๋งˆ์ธ๋“œ๋Š” ๊ฐœ๋ฐœ์ž๋กœ์„œ๋Š” ๋ถ€์ ํ•ฉํ•œ ๋งˆ์ธ๋“œ ๊ฐ™๋‹ค.

ํ•„์š”ํ•œ ๋ชจ๋“  ๊ฒƒ์€ ์ƒํ™ฉ์— ๋”ฐ๋ผ ํ•™์Šตํ•˜๊ณ  ์ ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

 

๋ฐ˜์‘ํ˜•