2026/03/18

오늘의 이야기

TCP(Transmission Control Protocol) / IP(Internet Protocol)



 


인터넷 - 나무위키


이 저작물은 CC BY-NC-SA 2.0 KR에 따라 이용할 수 있습니다. (단, 라이선스가 명시된 일부 문서 및 삽화 제외) 기여하신 문서의 저작권은 각 기여자에게 있으며, 각 기여자는 기여하신 부분의 저작권


namu.wiki




인터넷 통신을 하기 위한 프로토콜 중에 하나인 것은 알겠으나, 여태 한 번도 TCP/IP 통신앱을 만들어 보지는 않았습니다. 


최근에 주변장치들과 통신을 하는 앱을 구현해 줄 수 있는 지 물어보는 사용자가 있었습니다.  재택을 하루 종일 하고 있었다면, 자료를 찾아서 앱을 구현해 드리고 싶었으나, 


 


요새는 저녁 시간밖에는 시간을 낼 수 없는 지라... 하루 저녁 자료를 찾아보니 택도 없는 일인 듯하여, 돌려보냈지요. 


그리고 주말에 찾아 보았습니다. 


 


이런저런 코드들을 살펴보다가 참고가 될 듯한 코드를 찾아 앱을 하나 구현해 보았습니다. 


 


<uses-permission android:name="android.permission.INTERNET"/>

통신을 해야 하니 일단, manifest 파일에 internet 사용과 관련된 권한을 등록해 보았습니다.


 


Log.e("", "doTcpIpOpen ...")

GlobalScope.launch {

try{
socket = Socket( ipAddress, 3000)

doResponse()

} catch (e : IOException) {
Log.e("", "네트워크 응답 없음")
} catch (e : UnknownHostException) {
Log.e("", "알 수 없는 호스트 IP")
} catch (e : SecurityException) {
Log.e("", "보안 접속 오류 proxy 접속 거부")
} catch (e : IllegalArgumentException) {
Log.e("", "server port range 0 ~ 65535 ")
} catch (e : Exception) {
Log.e("", "error ${e.localizedMessage}")
}

Log.e("", "doTcpIpOpen end...")
}

다음은 소캣을 하나 생성하면서 접속할 서버와 연결을 시도해 보았습니다.  저 코드에서 말하는 ipAddress는 우리가 알고 있는 일반적인 ip 주소 (192.168.0.2 같은)입니다.  저는 PC에서 서버 측 구현을 python을 이용해서 echo 서버를 하나 만들어 놓고 테스트를 진행하였습니다. 


 


아래 코드는 python 을 구동하는 server 코드 예제입니다.  다른 기능은 없고 수신된 값을 다시 보내는 echo 서버입니다.


import socket
from random import random

addr = ("0.0.0.0", 3000) # 포트번호 4444
with socket.socket() as s: # 소켓 할당

s.bind(addr) # 소켓 바인딩
s.listen() # client의 연결요청 대기
print("Server is started... 3000 ")

# ------------------------------------서버 개통과정--------------

conn, addr = s.accept() # client 연경 요청을 수락
print("accept {}:{}".format(addr[0], addr[1])) # 연결된 client 정보 출력
while (1): # 무한반복
data = conn.recv(1024) # client가 보낸 메시지를 data에 저장
if data.decode() == "finished": # data decoding 결과가 finished면
break # 반복문 탈출
respData = data.decode() + "..." + str(random())
conn.send(respData.encode()) # data를 그대로 client에게 전송
print(data.decode()) # 보낸 데이터 읽기
print("Server finished") # 서버 종료 알리기

print("SOCKET closed... END")

서버와 클라이언트 간의 통신을 하여야 하기 때문에   서버 측 ip와 포트를 열어 줍니다.  잠깐 본 기억이기는 하나, 서버 측에서 선언한 addr 0.0.0.0의 선언에도 주의가 필요해 보이기는 합니다.   0.0.0.0을 선언하는 경우는 클라이언트의 ip 대역은 전체 대역을 어디서나 접근이 가능해지지만, 다르게 선언하는 경우 그 접속 범주가 달라지는 것을 알 수 있었습니다.


 


아무튼 서버를 구동한 상태에서 안드로이드 클라이언트를 실행해 접속을 해 보면 서버 측에 접속이 되는 것을 볼 수 있었습니다.


 


안드로이드에서 소켓 통신을 하면서 주의할 부분은 thread로 감싸 주어야 한다는 것입니다. 안드로이드는 앱이 실행하는 동안에 대기상태가 되는 것을 싫어합니다.  그래서 thread을 이용해 통신을 해 주어야 하는 것 같습니다.


 


GlobalScope.launch {
try {

val byteArr = ByteArray(100)

while(true) {

val input = withContext(Dispatchers.IO) {
socket.getInputStream()
}
ip = socket.inetAddress.hostAddress as String
val byte = withContext(Dispatchers.IO) {
input.read(byteArr)
}

val data = String(byteArr, 0, byte, Charset.forName("UTF-8"))

Log.e("", "ip=$ip readData=$byte $data" )
}
} catch (e : IOException) {
Log.e("", "read error = ${e.localizedMessage}")
} catch (e : StringIndexOutOfBoundsException) {
Log.e("", "read error = ${e.localizedMessage}")
doClose()
}
}

 


서버 접속이 되었다면, 이제 데이터 수신을 위한 스레드를 하나 구동시켜 둡니다. 그러면 언제든지 수신되는 데이터를 받아서 표시할 수 있을 테니까요..


 


GlobalScope.launch {
try {
val writer = OutputStreamWriter(socket.getOutputStream())
if ("" == strMessage) {
writer.write("hello server")
} else {
writer.write(strMessage)
}
writer.flush()
} catch (e : IOException) {
Log.e("", "네트워크 응답 없음")
} catch (e : UnknownHostException) {
Log.e("", "알 수 없는 호스트 IP")
} catch (e : SecurityException) {
Log.e("", "보안 접속 오류 proxy 접속 거부")
} catch (e : IllegalArgumentException) {
Log.e("", "server port range 0 ~ 65535 ")
} catch (e : Exception) {
Log.e("", "error ${e.localizedMessage}")
}
}

이제 서버 측을 데이터를 보내 보겠습니다. 


 


서버가 구동되어 있는 상황이라면 정상적으로 데이터를 주고받는 것을 볼 수 있습니다. 그렇지 않다고 하면 여러 종류의 에러(Exception)가 발생할 텐데요. 그 종류는 위에 기술된 정도일 듯합니다.  


 


오늘은 기초 공부를 해 보는 것이니 이 정도 구현을 해 보도록 하겠습니다. 


 


https://github.com/nari4169/TcpIpClientExam



 


GitHub - nari4169/TcpIpClientExam: TcpIp Client Sample Kotlin


TcpIp Client Sample Kotlin. Contribute to nari4169/TcpIpClientExam development by creating an account on GitHub.


github.com




오늘 구현했던 코드는 github에서 참고해 보세요.   다음에는 조금 더 정리된 글을 적어 보도록 하겠습니다.


 





댓글 없음:

댓글 쓰기

오늘의 이야기

오늘 아침 뉴스 보셨나요? 어제 밤사이 비가 많이 내려서 출근길 교통체증이 심하다는 소식이었는데요. 저도 출근하는데 평소보다 차가 너무 막혀서 지각할까봐 조마조마했답니다. 다행히 회사 근처에 다와서야 길이 뚫려서 무사히 도착했어요. 여러분 모두 안전하...