Python์ asyncio ์ ์์ค ๋คํธ์ํน์ ๋ง์คํฐํ์ธ์. Transport์ Protocol์ ์ฌ์ธต ๋ถ์ํ๊ณ , ๊ณ ์ฑ๋ฅ, ์ฌ์ฉ์ ์ ์ ๋คํธ์ํฌ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถ์ ์ํ ์ค์ฉ์ ์ธ ์์ ๋ฅผ ์ ๊ณตํฉ๋๋ค.
Python์ Asyncio Transport ์ดํดํ๊ธฐ: ์ ์์ค ๋คํธ์ํน ์ฌ์ธต ๋ถ์
ํ๋ Python ์ธ๊ณ์์ asyncio
๋ ๊ณ ์ฑ๋ฅ ๋คํธ์ํฌ ํ๋ก๊ทธ๋๋ฐ์ ํต์ฌ์ด ๋์์ต๋๋ค. ๊ฐ๋ฐ์๋ ์ข
์ข
aiohttp
๋๋ FastAPI
์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํจ๊ป async
๋ฐ await
๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์์ฑ์ด ๋ฐ์ด๋ ์ ํ๋ฆฌ์ผ์ด์
์ ๋๋๋๋ก ์ฝ๊ฒ ๊ตฌ์ถํ๋ฉด์ ์๋ฆ๋ค์ด ๊ณ ์์ค API๋ก ์์ํฉ๋๋ค. asyncio.open_connection()
๊ณผ ๊ฐ์ ํจ์์์ ์ ๊ณตํ๋ StreamReader
๋ฐ StreamWriter
๊ฐ์ฒด๋ ๋คํธ์ํฌ I/O๋ฅผ ์ฒ๋ฆฌํ๋ ๋งค์ฐ ๊ฐ๋จํ๊ณ ์์ฐจ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ํ์ง๋ง ์ถ์ํ๊ฐ ์ถฉ๋ถํ์ง ์์ผ๋ฉด ์ด๋ป๊ฒ ๋ ๊น์? ๋ณต์กํ๊ณ ์ํ๊ฐ ์๊ฑฐ๋ ํ์ค์ด ์๋ ๋คํธ์ํฌ ํ๋กํ ์ฝ์ ๊ตฌํํด์ผ ํ๋ ๊ฒฝ์ฐ ์ด๋ป๊ฒ ํด์ผ ํ ๊น์? ๊ธฐ๋ณธ ์ฐ๊ฒฐ์ ์ง์ ์ ์ดํ์ฌ ์ฑ๋ฅ์ ์ต๋ํ ๋์ด๋ด์ผ ํ๋ ๊ฒฝ์ฐ ์ด๋ป๊ฒ ํด์ผ ํ ๊น์? ์ด๊ฒ์ด ๋ฐ๋ก asyncio์ ๋คํธ์ํน ๊ธฐ๋ฅ์ ์ง์ ํ ๊ธฐ๋ฐ์ธ ์ ์์ค Transport ๋ฐ Protocol API๊ฐ ์๋ ๊ณณ์
๋๋ค. ์ฒ์์๋ ์ํ์ ์ผ๋ก ๋ณด์ผ ์ ์์ง๋ง ์ด ๊ฐ๋ ฅํ ๋์ค๋ฅผ ์ดํดํ๋ฉด ์๋ก์ด ์์ค์ ์ ์ด์ ์ ์ฐ์ฑ์ ์ป์ ์ ์์ผ๋ฉฐ ์์ํ ์ ์๋ ๊ฑฐ์ ๋ชจ๋ ๋คํธ์ํฌ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ถํ ์ ์์ต๋๋ค. ์ด ํฌ๊ด์ ์ธ ๊ฐ์ด๋๋ ์ถ์ํ์ ๊ณ์ธต์ ๋ฒ๊ฒจ๋ด๊ณ , Transport์ Protocol ๊ฐ์ ๊ณต์ ๊ด๊ณ๋ฅผ ํ๊ตฌํ๋ฉฐ, ์ค์ฉ์ ์ธ ์์ ๋ฅผ ์๋ดํ์ฌ Python์์ ์ ์์ค ๋น๋๊ธฐ์ ๋คํธ์ํน์ ๋ง์คํฐํ ์ ์๋๋ก ์ง์ํฉ๋๋ค.
Asyncio ๋คํธ์ํน์ ๋ ๊ฐ์ง ์ธก๋ฉด: ๊ณ ์์ค vs. ์ ์์ค
์ ์์ค API๋ฅผ ์์ธํ ์ดํด๋ณด๊ธฐ ์ ์ asyncio ์ํ๊ณ ๋ด์์ ์ ์์ค API๊ฐ ์ฐจ์งํ๋ ์์น๋ฅผ ์ดํดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. Asyncio๋ ๋คํธ์ํฌ ํต์ ์ ์ํด ๊ฐ๊ฐ ๋ค๋ฅธ ์ฌ์ฉ ์ฌ๋ก์ ๋ง๊ฒ ์กฐ์ ๋ ๋ ๊ฐ์ ๋ณ๋ ๊ณ์ธต์ ์ง๋ฅ์ ์ผ๋ก ์ ๊ณตํฉ๋๋ค.
๊ณ ์์ค API: ์คํธ๋ฆผ
์ผ๋ฐ์ ์ผ๋ก "์คํธ๋ฆผ"์ด๋ผ๊ณ ํ๋ ๊ณ ์์ค API๋ ๋๋ถ๋ถ์ ๊ฐ๋ฐ์๊ฐ ์ฒ์ ์ ํ๋ ๊ฒ์
๋๋ค. asyncio.open_connection()
๋๋ asyncio.start_server()
๋ฅผ ์ฌ์ฉํ๋ฉด StreamReader
๋ฐ StreamWriter
๊ฐ์ฒด๋ฅผ ๋ฐ์ต๋๋ค. ์ด API๋ ๋จ์์ฑ๊ณผ ์ฌ์ฉ ํธ์์ฑ์ ์ํด ์ค๊ณ๋์์ต๋๋ค.
- ๋ช
๋ นํ ์คํ์ผ: ์ฝ๋๋ฅผ ์์ฐจ์ ์ผ๋ก ์์ฑํ ์ ์์ต๋๋ค. 100๋ฐ์ดํธ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด
await reader.read(100)
์ ์ํํ ๋ค์ ์๋ต์ ๋ณด๋ด๊ธฐ ์ํดwriter.write(data)
์ ์ํํฉ๋๋ค. ์ดasync/await
ํจํด์ ์ง๊ด์ ์ด๊ณ ์ดํดํ๊ธฐ ์ฝ์ต๋๋ค. - ํธ๋ฆฌํ ๋์ฐ๋ฏธ:
readuntil(separator)
๋ฐreadexactly(n)
๊ณผ ๊ฐ์ ๋ฉ์๋๋ฅผ ์ ๊ณตํ์ฌ ์ผ๋ฐ์ ์ธ ํ๋ ์ด๋ฐ ์์ ์ ์ฒ๋ฆฌํ๋ฏ๋ก ๋ฒํผ๋ฅผ ์๋์ผ๋ก ๊ด๋ฆฌํ ํ์๊ฐ ์์ต๋๋ค. - ์ด์์ ์ธ ์ฌ์ฉ ์ฌ๋ก: ๊ฐ๋จํ ์์ฒญ-์๋ต ํ๋กํ ์ฝ(์: ๊ธฐ๋ณธ HTTP ํด๋ผ์ด์ธํธ), ๋ผ์ธ ๊ธฐ๋ฐ ํ๋กํ ์ฝ(์: Redis ๋๋ SMTP) ๋๋ ํต์ ์ด ์์ธก ๊ฐ๋ฅํ ์ ํ ํ๋ฆ์ ๋ฐ๋ฅด๋ ๋ชจ๋ ์ํฉ์ ์ ํฉํฉ๋๋ค.
๊ทธ๋ฌ๋ ์ด๋ฌํ ๋จ์ํจ์๋ trade-off๊ฐ ๋ฐ๋ฆ
๋๋ค. ์คํธ๋ฆผ ๊ธฐ๋ฐ ์ ๊ทผ ๋ฐฉ์์ ์๊ธฐ์น ์์ ๋ฉ์์ง๊ฐ ์ธ์ ๋ ์ง ๋์ฐฉํ ์ ์๋ ๊ณ ๋๋ก ๋์์ ์ด๊ณ ์ด๋ฒคํธ ์ค์ฌ์ ์ธ ํ๋กํ ์ฝ์ ๊ฒฝ์ฐ ๋ ํจ์จ์ ์ผ ์ ์์ต๋๋ค. ์์ฐจ์ ์ธ await
๋ชจ๋ธ์ ๋์ ์ฝ๊ธฐ ๋ฐ ์ฐ๊ธฐ๋ฅผ ์ฒ๋ฆฌํ๊ฑฐ๋ ๋ณต์กํ ์ฐ๊ฒฐ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐ ๋ฒ๊ฑฐ๋ก์ธ ์ ์์ต๋๋ค.
์ ์์ค API: Transport ๋ฐ Protocol
์ด๊ฒ์ ๊ณ ์์ค ์คํธ๋ฆผ API๊ฐ ์ค์ ๋ก ๊ตฌ์ถ๋ ๊ธฐ๋ฐ ๊ณ์ธต์ ๋๋ค. ์ ์์ค API๋ Transport์ Protocol์ ๋ ๊ฐ์ง ๋ณ๋ ๊ตฌ์ฑ ์์์ ๊ธฐ๋ฐํ ๋์์ธ ํจํด์ ์ฌ์ฉํฉ๋๋ค.
- ์ด๋ฒคํธ ์ค์ฌ ์คํ์ผ: ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด ํจ์๋ฅผ ํธ์ถํ๋ ๋์ , ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด asyncio๊ฐ ๊ฐ์ฒด์์ ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค(์: ์ฐ๊ฒฐ์ด ์ค์ ๋จ, ๋ฐ์ดํฐ ์์ ). ์ด๊ฒ์ ์ฝ๋ฐฑ ๊ธฐ๋ฐ ์ ๊ทผ ๋ฐฉ์์ ๋๋ค.
- ๊ด์ฌ์ฌ ๋ถ๋ฆฌ: "๋ฌด์"๊ณผ "์ด๋ป๊ฒ"๋ฅผ ๊น๋ํ๊ฒ ๋ถ๋ฆฌํฉ๋๋ค. Protocol์ ๋ฐ์ดํฐ๋ก ๋ฌด์์ ํ ์ง(์ ํ๋ฆฌ์ผ์ด์ ๋ก์ง)๋ฅผ ์ ์ํ๋ ๋ฐ๋ฉด, Transport๋ ๋ฐ์ดํฐ๊ฐ ๋คํธ์ํฌ๋ฅผ ํตํด ์ด๋ป๊ฒ ์ ์ก๋๊ณ ์์ ๋๋์ง(I/O ๋ฉ์ปค๋์ฆ)๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค.
- ์ต๋ ์ ์ด: ์ด API๋ ๋ฒํผ๋ง, ํ๋ฆ ์ ์ด(๋ฐฑํ๋ ์ ) ๋ฐ ์ฐ๊ฒฐ ์๋ช ์ฃผ๊ธฐ์ ๋ํ ์ธ๋ฐํ ์ ์ด๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ์ด์์ ์ธ ์ฌ์ฉ ์ฌ๋ก: ์ฌ์ฉ์ ์ง์ ๋ฐ์ด๋๋ฆฌ ๋๋ ํ ์คํธ ํ๋กํ ์ฝ์ ๊ตฌํํ๊ณ , ์์ฒ ๊ฐ์ ์๊ตฌ ์ฐ๊ฒฐ์ ์ฒ๋ฆฌํ๋ ๊ณ ์ฑ๋ฅ ์๋ฒ๋ฅผ ๊ตฌ์ถํ๊ฑฐ๋, ๋คํธ์ํฌ ํ๋ ์์ํฌ ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ฐ๋ฐํ๋ ๋ฐ ํ์์ ์ ๋๋ค.
์ด๋ ๊ฒ ์๊ฐํ์ธ์. ์คํธ๋ฆผ API๋ ์์ฌ ํคํธ ์๋น์ค์ ๊ฐ์ต๋๋ค. ๋ฏธ๋ฆฌ ๋ถ๋ถ์ ์ผ๋ก ๋๋ ์ฌ๋ฃ์ ๋ฐ๋ผ์ผ ํ ๊ฐ๋จํ ๋ ์ํผ๋ฅผ ๋ฐ์ต๋๋ค. Transport ๋ฐ Protocol API๋ ์์์ฌ์ ํ๋ก์ธ์ค์ ๋ชจ๋ ๋จ๊ณ๋ฅผ ์๋ฒฝํ๊ฒ ์ ์ดํ ์ ์๋ ์ ๋ฌธ ์ฃผ๋ฐฉ์ ์ ฐํ์ ๊ฐ์ต๋๋ค. ๋ ๋ค ํ๋ฅญํ ์์ฌ๋ฅผ ๋ง๋ค ์ ์์ง๋ง ํ์๋ ๋ฌดํํ ์ฐฝ์์ฑ๊ณผ ์ ์ด๋ฅผ ์ ๊ณตํฉ๋๋ค.
ํต์ฌ ๊ตฌ์ฑ ์์: Transport ๋ฐ Protocol ์์ธํ ์ดํด๋ณด๊ธฐ
์ ์์ค API์ ๊ฐ๋ ฅํจ์ Protocol๊ณผ Transport ๊ฐ์ ์ฐ์ํ ์ํธ ์์ฉ์์ ๋น๋กฏ๋ฉ๋๋ค. ์ ์์ค asyncio ๋คํธ์ํฌ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ณ๊ฐ์ ํํธ๋์ด์ง๋ง ๋ถ๊ฐ๋ถ์ ๊ด๊ณ์ ๋๋ค.
Protocol: ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋
Protocol์ ์ฌ์ฉ์๊ฐ ์์ฑํ๋ ํด๋์ค์
๋๋ค. asyncio.Protocol
(๋๋ ํด๋น ๋ณํ ์ค ํ๋)์์ ์์๋ฐ์ผ๋ฉฐ ๋จ์ผ ๋คํธ์ํฌ ์ฐ๊ฒฐ์ ์ฒ๋ฆฌํ๊ธฐ ์ํ ์ํ ๋ฐ ๋ก์ง์ ํฌํจํฉ๋๋ค. ์ด ํด๋์ค๋ฅผ ์ง์ ์ธ์คํด์คํํ์ง ์์ต๋๋ค. asyncio์ ์ ๊ณตํฉ๋๋ค(์: loop.create_server
์). ๊ทธ๋ฌ๋ฉด asyncio๋ ๊ฐ ์ ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ์ ๋ํด ํ๋กํ ์ฝ์ ์ ์ธ์คํด์ค๋ฅผ ๋ง๋ญ๋๋ค.
ํ๋กํ ์ฝ ํด๋์ค๋ ์ด๋ฒคํธ ๋ฃจํ๊ฐ ์ฐ๊ฒฐ ์๋ช ์ฃผ๊ธฐ์ ์ฌ๋ฌ ์์ ์์ ํธ์ถํ๋ ์ผ๋ จ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ ๋ฉ์๋๋ก ์ ์๋ฉ๋๋ค. ๊ฐ์ฅ ์ค์ํ ๊ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
connection_made(self, transport)
์ ์ฐ๊ฒฐ์ด ์ฑ๊ณต์ ์ผ๋ก ์ค์ ๋๋ฉด ์ ํํ ํ ๋ฒ ํธ์ถ๋ฉ๋๋ค. ์ด๊ฒ์ด ์ง์
์ ์
๋๋ค. ์ฐ๊ฒฐ์ ๋ํ๋ด๋ transport
๊ฐ์ฒด๋ฅผ ๋ฐ๋ ๊ณณ์
๋๋ค. ์ผ๋ฐ์ ์ผ๋ก self.transport
๋ก ์ฐธ์กฐ๋ฅผ ์ ์ฅํด์ผ ํฉ๋๋ค. ๋ฒํผ ์ค์ ๋๋ ํผ์ด์ ์ฃผ์ ๋ก๊น
๊ณผ ๊ฐ์ ์ฐ๊ฒฐ๋ณ ์ด๊ธฐํ๋ฅผ ์ํํ๊ธฐ์ ์ด์์ ์ธ ์ฅ์์
๋๋ค.
data_received(self, data)
ํ๋กํ ์ฝ์ ํต์ฌ์
๋๋ค. ์ด ๋ฉ์๋๋ ์ฐ๊ฒฐ ๋ฐ๋ํธ์์ ์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ ๋๋ง๋ค ํธ์ถ๋ฉ๋๋ค. data
์ธ์๋ bytes
๊ฐ์ฒด์
๋๋ค. TCP๋ ๋ฉ์์ง ํ๋กํ ์ฝ์ด ์๋ ์คํธ๋ฆผ ํ๋กํ ์ฝ์ด๋ผ๋ ์ ์ ๊ธฐ์ตํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ ํ๋ฆฌ์ผ์ด์
์ ๋จ์ผ ๋
ผ๋ฆฌ์ ๋ฉ์์ง๋ ์ฌ๋ฌ data_received
ํธ์ถ์ ๊ฑธ์ณ ๋ถํ ๋๊ฑฐ๋ ์ฌ๋ฌ ๊ฐ์ ์์ ๋ฉ์์ง๊ฐ ๋จ์ผ ํธ์ถ๋ก ๋ฒ๋ค๋ ์ ์์ต๋๋ค. ์ฝ๋๋ ์ด ๋ฒํผ๋ง ๋ฐ ๊ตฌ๋ฌธ ๋ถ์์ ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค.
connection_lost(self, exc)
์ฐ๊ฒฐ์ด ๋ซํ๋ฉด ํธ์ถ๋ฉ๋๋ค. ์ด๊ฒ์ ์ฌ๋ฌ ๊ฐ์ง ์ด์ ๋ก ๋ฐ์ํ ์ ์์ต๋๋ค. ์ฐ๊ฒฐ์ด ๊น๋ํ๊ฒ ๋ซํ๋ฉด(์: ๋ฐ๋ํธ์์ ๋ซํ๊ฑฐ๋ transport.close()
๋ฅผ ํธ์ถํ๋ ๊ฒฝ์ฐ) exc
๋ None
์ด ๋ฉ๋๋ค. ์ฐ๊ฒฐ์ด ์ค๋ฅ๋ก ์ธํด ๋ซํ๋ฉด(์: ๋คํธ์ํฌ ์ค๋ฅ, ์ฌ์ค์ ) exc
๋ ์ค๋ฅ๋ฅผ ์์ธํ ์ค๋ช
ํ๋ ์์ธ ๊ฐ์ฒด๊ฐ ๋ฉ๋๋ค. ์ด๊ฒ์ ์ ๋ฆฌ ์์
์ ์ํํ๊ณ , ์ฐ๊ฒฐ์ ๋๊ณ ๊ธฐ๋กํ๊ฑฐ๋, ํด๋ผ์ด์ธํธ๋ฅผ ๊ตฌ์ถํ๋ ๊ฒฝ์ฐ ๋ค์ ์ฐ๊ฒฐ์ ์๋ํ ๊ธฐํ์
๋๋ค.
eof_received(self)
์ด๊ฒ์ ๋ณด๋ค ๋ฏธ๋ฌํ ์ฝ๋ฐฑ์
๋๋ค. ๋ค๋ฅธ ์ชฝ ๋์์ ๋ ์ด์ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด์ง ์์ ๊ฒ์์ ์๋ฆฌ๋ ๊ฒฝ์ฐ(์: POSIX ์์คํ
์์ shutdown(SHUT_WR)
์ ํธ์ถํ์ฌ) ํธ์ถ๋์ง๋ง ์ฐ๊ฒฐ์ด ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋๋ก ์ด๋ ค ์์ ์ ์์ต๋๋ค. ์ด ๋ฉ์๋์์ True
๋ฅผ ๋ฐํํ๋ฉด transport๊ฐ ๋ซํ๋๋ค. False
(๊ธฐ๋ณธ๊ฐ)๋ฅผ ๋ฐํํ๋ฉด ๋์ค์ ์ง์ transport๋ฅผ ๋ซ๋ ์ญํ ์ ํฉ๋๋ค.
Transport: ํต์ ์ฑ๋
Transport๋ asyncio์์ ์ ๊ณตํ๋ ๊ฐ์ฒด์
๋๋ค. ๋ง๋ค์ง ์๊ณ ํ๋กํ ์ฝ์ connection_made
๋ฉ์๋์์ ๋ฐ์ต๋๋ค. ๊ธฐ๋ณธ ๋คํธ์ํฌ ์์ผ ๋ฐ ์ด๋ฒคํธ ๋ฃจํ์ I/O ์ค์ผ์ค๋ง์ ๋ํ ๊ณ ์์ค ์ถ์ํ ์ญํ ์ ํฉ๋๋ค. ์ฃผ์ ์์
์ ๋ฐ์ดํฐ ์ ์ก๊ณผ ์ฐ๊ฒฐ ์ ์ด๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฒ์
๋๋ค.
๋ฉ์๋๋ฅผ ํตํด transport์ ์ํธ ์์ฉํฉ๋๋ค.
transport.write(data)
๋ฐ์ดํฐ๋ฅผ ์ ์กํ๋ ๊ธฐ๋ณธ ๋ฉ์๋์
๋๋ค. data
๋ bytes
๊ฐ์ฒด์ฌ์ผ ํฉ๋๋ค. ์ด ๋ฉ์๋๋ non-blocking์
๋๋ค. ๋ฐ์ดํฐ๋ฅผ ์ฆ์ ์ ์กํ์ง ์์ต๋๋ค. ๋์ ๋ฐ์ดํฐ๋ฅผ ๋ด๋ถ ์ฐ๊ธฐ ๋ฒํผ์ ๋ฐฐ์นํ๊ณ ์ด๋ฒคํธ ๋ฃจํ๋ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ๊ฐ๋ฅํ ํ ํจ์จ์ ์ผ๋ก ๋คํธ์ํฌ๋ฅผ ํตํด ๋ณด๋
๋๋ค.
transport.writelines(list_of_data)
์ผ๋ จ์ bytes
๊ฐ์ฒด๋ฅผ ํ ๋ฒ์ ๋ฒํผ์ ์ฐ๋ ๋ณด๋ค ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ผ๋ก, ์ ์ฌ์ ์ผ๋ก ์์คํ
ํธ์ถ ์๋ฅผ ์ค์ผ ์ ์์ต๋๋ค.
transport.close()
์ด๊ฒ์ ์ ์์ ์ธ ์ข
๋ฃ๋ฅผ ์์ํฉ๋๋ค. transport๋ ๋จผ์ ์ฐ๊ธฐ ๋ฒํผ์ ๋จ์ ์๋ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ํ๋ฌ์ํ ๋ค์ ์ฐ๊ฒฐ์ ๋ซ์ต๋๋ค. close()
๊ฐ ํธ์ถ๋ ํ์๋ ๋ ์ด์ ๋ฐ์ดํฐ๋ฅผ ์ธ ์ ์์ต๋๋ค.
transport.abort()
์ด๊ฒ์ ํ๋ ์ข ๋ฃ๋ฅผ ์ํํฉ๋๋ค. ์ฐ๊ฒฐ์ด ์ฆ์ ๋ซํ๊ณ ์ฐ๊ธฐ ๋ฒํผ์ ๋๊ธฐ ์ค์ธ ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ ์ญ์ ๋ฉ๋๋ค. ์์ธ์ ์ธ ์ํฉ์์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
transport.get_extra_info(name, default=None)
์กฐ์ฌ๋ฅผ ์ํ ๋งค์ฐ ์ ์ฉํ ๋ฐฉ๋ฒ์
๋๋ค. ํผ์ด์ ์ฃผ์('peername'
), ๊ธฐ๋ณธ ์์ผ ๊ฐ์ฒด('socket'
) ๋๋ SSL/TLS ์ธ์ฆ์ ์ ๋ณด('ssl_object'
)์ ๊ฐ์ ์ฐ๊ฒฐ์ ๋ํ ์ ๋ณด๋ฅผ ์ป์ ์ ์์ต๋๋ค.
๊ณต์ ๊ด๊ณ
์ด ๋์์ธ์ ์๋ฆ๋ค์์ ์ ๋ณด์ ๋ช ํํ๊ณ ์ํ์ ์ธ ํ๋ฆ์ ๋๋ค.
- ์ค์ : ์ด๋ฒคํธ ๋ฃจํ๋ ์ ์ฐ๊ฒฐ์ ์๋ฝํฉ๋๋ค.
- ์ธ์คํด์คํ: ๋ฃจํ๋
Protocol
ํด๋์ค์ ์ธ์คํด์ค์ ์ฐ๊ฒฐ์ ๋ํ๋ด๋Transport
๊ฐ์ฒด๋ฅผ ๋ง๋ญ๋๋ค. - ๋งํฌ: ๋ฃจํ๋
your_protocol.connection_made(transport)
๋ฅผ ํธ์ถํ์ฌ ๋ ๊ฐ์ฒด๋ฅผ ํจ๊ป ์ฐ๊ฒฐํฉ๋๋ค. ์ด์ ํ๋กํ ์ฝ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ผ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. - ๋ฐ์ดํฐ ์์ : ๋ฐ์ดํฐ๊ฐ ๋คํธ์ํฌ ์์ผ์ ๋์ฐฉํ๋ฉด ์ด๋ฒคํธ ๋ฃจํ๊ฐ ๊นจ์ด๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ
your_protocol.data_received(data)
๋ฅผ ํธ์ถํฉ๋๋ค. - ์ฒ๋ฆฌ: ํ๋กํ ์ฝ์ ๋ก์ง์ ์์ ๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค.
- ๋ฐ์ดํฐ ์ ์ก: ๋ก์ง์ ๋ฐ๋ผ ํ๋กํ ์ฝ์
self.transport.write(response_data)
๋ฅผ ํธ์ถํ์ฌ ์๋ต์ ๋ณด๋ ๋๋ค. ๋ฐ์ดํฐ๊ฐ ๋ฒํผ๋ง๋ฉ๋๋ค. - ๋ฐฑ๊ทธ๋ผ์ด๋ I/O: ์ด๋ฒคํธ ๋ฃจํ๋ ๋ฒํผ๋ง๋ ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๋ non-blocking ์ฒ๋ฆฌ๋ฅผ transport๋ฅผ ํตํด ์ฒ๋ฆฌํฉ๋๋ค.
- ํด์ : ์ฐ๊ฒฐ์ด ์ข
๋ฃ๋๋ฉด ์ด๋ฒคํธ ๋ฃจํ๋ ์ต์ข
์ ๋ฆฌ๋ฅผ ์ํด
your_protocol.connection_lost(exc)
๋ฅผ ํธ์ถํฉ๋๋ค.
์ค์ฉ์ ์ธ ์์ ๊ตฌ์ถ: ์์ฝ ์๋ฒ ๋ฐ ํด๋ผ์ด์ธํธ
์ด๋ก ์ ํ๋ฅญํ์ง๋ง Transport์ Protocol์ ์ดํดํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ๋ฌด์ธ๊ฐ๋ฅผ ๊ตฌ์ถํ๋ ๊ฒ์ ๋๋ค. ๊ณ ์ ์ ์ธ ์์ฝ ์๋ฒ์ ํด๋น ํด๋ผ์ด์ธํธ๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค. ์๋ฒ๋ ์ฐ๊ฒฐ์ ์๋ฝํ๊ณ ์์ ๋ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๋ณด๋ ๋๋ค.
์์ฝ ์๋ฒ ๊ตฌํ
๋จผ์ ์๋ฒ ์ธก ํ๋กํ ์ฝ์ ์ ์ํฉ๋๋ค. ํต์ฌ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ณด์ฌ์ฃผ๋ ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค.
import asyncio
class EchoServerProtocol(asyncio.Protocol):
def connection_made(self, transport):
# ์ ์ฐ๊ฒฐ์ด ์ค์ ๋์์ต๋๋ค.
# ๋ก๊น
์ ์ํด ์๊ฒฉ ์ฃผ์๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
peername = transport.get_extra_info('peername')
print(f"Connection from: {peername}")
# ๋์ค์ ์ฌ์ฉํ ์ ์๋๋ก transport๋ฅผ ์ ์ฅํฉ๋๋ค.
self.transport = transport
def data_received(self, data):
# ํด๋ผ์ด์ธํธ์์ ๋ฐ์ดํฐ๊ฐ ์์ ๋ฉ๋๋ค.
message = data.decode()
print(f"Data received: {message.strip()}")
# ๋ฐ์ดํฐ๋ฅผ ํด๋ผ์ด์ธํธ๋ก ๋ค์ ์์ฝํฉ๋๋ค.
print(f"Echoing back: {message.strip()}")
self.transport.write(data)
def connection_lost(self, exc):
# ์ฐ๊ฒฐ์ด ๋ซํ์ต๋๋ค.
print("Connection closed.")
# transport๋ ์๋์ผ๋ก ๋ซํ๋ฏ๋ก ์ฌ๊ธฐ์์ self.transport.close()๋ฅผ ํธ์ถํ ํ์๊ฐ ์์ต๋๋ค.
async def main_server():
# ์๋ฒ๋ฅผ ๋ฌด๊ธฐํ ์คํํ ๊ณํ์ด๋ฏ๋ก ์ด๋ฒคํธ ๋ฃจํ์ ๋ํ ์ฐธ์กฐ๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
loop = asyncio.get_running_loop()
host = '127.0.0.1'
port = 8888
# `create_server` ์ฝ๋ฃจํด์ ์๋ฒ๋ฅผ ์์ฑํ๊ณ ์์ํฉ๋๋ค.
# ์ฒซ ๋ฒ์งธ ์ธ์๋ protocol_factory๋ก, ์ ํ๋กํ ์ฝ ์ธ์คํด์ค๋ฅผ ๋ฐํํ๋ ํธ์ถ ๊ฐ๋ฅ ๊ฐ์ฒด์
๋๋ค.
# ์ด ๊ฒฝ์ฐ ๋จ์ํ `EchoServerProtocol` ํด๋์ค๋ฅผ ์ ๋ฌํ๋ฉด ๋ฉ๋๋ค.
server = await loop.create_server(
lambda: EchoServerProtocol(),
host,
port)
addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets)
print(f'Serving on {addrs}')
# ์๋ฒ๋ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์คํ๋ฉ๋๋ค. ๋ฉ์ธ ์ฝ๋ฃจํด์ ํ์ฑ ์ํ๋ก ์ ์งํ๊ธฐ ์ํด
# ์๋ฃ๋์ง ์๋ ์ Future์ ๊ฐ์ ๊ฒ์ ๊ธฐ๋ค๋ฆด ์ ์์ต๋๋ค.
# ์ด ์์์๋ ๊ทธ๋ฅ "์์ํ" ์คํํฉ๋๋ค.
async with server:
await server.serve_forever()
if __name__ == "__main__":
try:
# ์๋ฒ๋ฅผ ์คํํ๋ ค๋ฉด:
asyncio.run(main_server())
except KeyboardInterrupt:
print("Server shut down.")
์ด ์๋ฒ ์ฝ๋์์ loop.create_server()
๊ฐ ํต์ฌ์
๋๋ค. ์ง์ ๋ ํธ์คํธ ๋ฐ ํฌํธ์ ๋ฐ์ธ๋ฉํ๊ณ ์ด๋ฒคํธ ๋ฃจํ์ ์ ์ฐ๊ฒฐ์ ์์ ๋๊ธฐํ๋๋ก ์ง์ํฉ๋๋ค. ๊ฐ ๋ค์ด์ค๋ ์ฐ๊ฒฐ์ ๋ํด protocol_factory
(lambda: EchoServerProtocol()
ํจ์)๋ฅผ ํธ์ถํ์ฌ ํด๋น ํน์ ํด๋ผ์ด์ธํธ์ ๋ํ ์๋ก์ด ํ๋กํ ์ฝ ์ธ์คํด์ค๋ฅผ ๋ง๋ญ๋๋ค.
์์ฝ ํด๋ผ์ด์ธํธ ๊ตฌํ
ํด๋ผ์ด์ธํธ ํ๋กํ ์ฝ์ ์์ฒด ์ํ๋ฅผ ๊ด๋ฆฌํด์ผ ํ๋ฏ๋ก ์ฝ๊ฐ ๋ ๋ณต์กํฉ๋๋ค. ์ฆ, ์ด๋ค ๋ฉ์์ง๋ฅผ ๋ณด๋ผ์ง, ์ธ์ ์์
์ "์๋ฃ"๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผํ ์ง์
๋๋ค. ์ผ๋ฐ์ ์ธ ํจํด์ asyncio.Future
๋๋ asyncio.Event
๋ฅผ ์ฌ์ฉํ์ฌ ํด๋ผ์ด์ธํธ๋ฅผ ์์ํ ๋ฉ์ธ ์ฝ๋ฃจํด์ผ๋ก ์๋ฃ๋ฅผ ๋ค์ ์ ํธํ๋ ๊ฒ์
๋๋ค.
import asyncio
class EchoClientProtocol(asyncio.Protocol):
def __init__(self, message, on_con_lost):
self.message = message
self.on_con_lost = on_con_lost
self.transport = None
def connection_made(self, transport):
self.transport = transport
print(f"Sending: {self.message}")
self.transport.write(self.message.encode())
def data_received(self, data):
print(f"Received echo: {data.decode().strip()}")
def connection_lost(self, exc):
print("The server closed the connection")
# ์ฐ๊ฒฐ์ด ์์ค๋๊ณ ์์
์ด ์๋ฃ๋์์์ ์๋ฆฝ๋๋ค.
self.on_con_lost.set_result(True)
def eof_received(self):
# ์๋ฒ๊ฐ ์ข
๋ฃ ์ ์ EOF๋ฅผ ๋ณด๋ด๋ ๊ฒฝ์ฐ ํธ์ถํ ์ ์์ต๋๋ค.
print("Received EOF from server.")
async def main_client():
loop = asyncio.get_running_loop()
# on_con_lost future๋ ํด๋ผ์ด์ธํธ ์์
์ ์๋ฃ๋ฅผ ์๋ฆฌ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
on_con_lost = loop.create_future()
message = "Hello World!"
host = '127.0.0.1'
port = 8888
# `create_connection`์ ์ฐ๊ฒฐ์ ์ค์ ํ๊ณ ํ๋กํ ์ฝ์ ์ฐ๊ฒฐํฉ๋๋ค.
try:
transport, protocol = await loop.create_connection(
lambda: EchoClientProtocol(message, on_con_lost),
host,
port)
except ConnectionRefusedError:
print("Connection refused. Is the server running?")
return
# ํ๋กํ ์ฝ์ด ์ฐ๊ฒฐ์ด ์์ค๋์์์ ์๋ฆด ๋๊น์ง ๋๊ธฐํฉ๋๋ค.
try:
await on_con_lost
finally:
# ์ ์์ ์ผ๋ก transport๋ฅผ ๋ซ์ต๋๋ค.
transport.close()
if __name__ == "__main__":
# ํด๋ผ์ด์ธํธ๋ฅผ ์คํํ๋ ค๋ฉด:
# ๋จผ์ , ํ ํฐ๋ฏธ๋์์ ์๋ฒ๋ฅผ ์์ํฉ๋๋ค.
# ๊ทธ๋ฐ ๋ค์, ๋ค๋ฅธ ํฐ๋ฏธ๋์์ ์ด ์คํฌ๋ฆฝํธ๋ฅผ ์คํํฉ๋๋ค.
asyncio.run(main_client())
์ฌ๊ธฐ์ loop.create_connection()
์ create_server
์ ํด๋ผ์ด์ธํธ ์ธก ๋์๋ฌผ์
๋๋ค. ์ฃผ์ด์ง ์ฃผ์์ ์ฐ๊ฒฐ์ ์๋ํฉ๋๋ค. ์ฑ๊ณตํ๋ฉด EchoClientProtocol
์ ์ธ์คํด์คํํ๊ณ connection_made
๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค. on_con_lost
Future์ ์ฌ์ฉ์ ์ค์ํ ํจํด์
๋๋ค. main_client
์ฝ๋ฃจํด์ ์ด future๋ฅผ await
ํ์ฌ ํ๋กํ ์ฝ์ด connection_lost
๋ด์์ on_con_lost.set_result(True)
๋ฅผ ํธ์ถํ์ฌ ์์
์ด ์๋ฃ๋์์์ ์๋ฆด ๋๊น์ง ์์ฒด ์คํ์ ํจ๊ณผ์ ์ผ๋ก ์ผ์ ์ค์งํฉ๋๋ค.
๊ณ ๊ธ ๊ฐ๋ ๋ฐ ์ค์ ์๋๋ฆฌ์ค
์์ฝ ์์ ๋ ๊ธฐ๋ณธ ์ฌํญ์ ๋ค๋ฃจ์ง๋ง ์ค์ ํ๋กํ ์ฝ์ ๊ฑฐ์ ๊ทธ๋ ๊ฒ ๊ฐ๋จํ์ง ์์ต๋๋ค. ํ์ฐ์ ์ผ๋ก ์ง๋ฉดํ๊ฒ ๋ ๋ช ๊ฐ์ง ๋ ๊ณ ๊ธ ์ฃผ์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๋ฉ์์ง ํ๋ ์ด๋ฐ ๋ฐ ๋ฒํผ๋ง ์ฒ๋ฆฌ
๊ธฐ๋ณธ ์ฌํญ ๋ค์์ผ๋ก ํ์
ํด์ผ ํ ๊ฐ์ฅ ์ค์ํ ๊ฐ๋
์ TCP๊ฐ ๋ฐ์ดํธ ์คํธ๋ฆผ์ด๋ผ๋ ๊ฒ์
๋๋ค. ๋ด์ฌ๋ "๋ฉ์์ง" ๊ฒฝ๊ณ๊ฐ ์์ต๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ "Hello"๋ฅผ ๋ณด๋ธ ๋ค์ "World"๋ฅผ ๋ณด๋ด๋ฉด ์๋ฒ์ data_received
๊ฐ ํ ๋ฒ b'HelloWorld'
๋ก, ๋ ๋ฒ b'Hello'
๋ฐ b'World'
๋ก, ๋๋ ๋ถ๋ถ ๋ฐ์ดํฐ๊ฐ ์๋ ์ฌ๋ฌ ๋ฒ ํธ์ถ๋ ์ ์์ต๋๋ค.
ํ๋กํ ์ฝ์ ์ด๋ฌํ ๋ฐ์ดํธ ์คํธ๋ฆผ์ ์๋ฏธ ์๋ ๋ฉ์์ง๋ก ์ฌ์กฐ๋ฆฝํ๋ "ํ๋ ์ด๋ฐ"์ ๋ด๋นํฉ๋๋ค. ์ผ๋ฐ์ ์ธ ์ ๋ต์ ์ค ๋ฐ๊ฟ ๋ฌธ์(
)์ ๊ฐ์ ๊ตฌ๋ถ ๊ธฐํธ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์
๋๋ค.
๋ค์์ ์ค ๋ฐ๊ฟ์ ์ฐพ์ ๋๊น์ง ๋ฐ์ดํฐ๋ฅผ ๋ฒํผ๋งํ์ฌ ํ ๋ฒ์ ํ ์ค์ฉ ์ฒ๋ฆฌํ๋ ์์ ๋ ํ๋กํ ์ฝ์ ๋๋ค.
class LineBasedProtocol(asyncio.Protocol):
def __init__(self):
self._buffer = b''
self.transport = None
def connection_made(self, transport):
self.transport = transport
print("Connection established.")
def data_received(self, data):
# ์ ๋ฐ์ดํฐ๋ฅผ ๋ด๋ถ ๋ฒํผ์ ์ถ๊ฐ
self._buffer += data
# ๋ฒํผ์ ์๋ ๋งํผ์ ์์ ํ ์ค์ ์ฒ๋ฆฌ
while b'\n' in self._buffer:
line, self._buffer = self._buffer.split(b'\n', 1)
self.process_line(line.decode().strip())
def process_line(self, line):
# ๋จ์ผ ๋ฉ์์ง์ ๋ํ ์ ํ๋ฆฌ์ผ์ด์
๋ก์ง์ด ์ฌ๊ธฐ์ ๋ค์ด๊ฐ๋๋ค
print(f"Processing complete message: {line}")
response = f"Processed: {line}\n"
self.transport.write(response.encode())
def connection_lost(self, exc):
print("Connection lost.")
ํ๋ฆ ์ ์ด(๋ฐฑํ๋ ์ ) ๊ด๋ฆฌ
์ ํ๋ฆฌ์ผ์ด์ ์ด ๋คํธ์ํฌ ๋๋ ์๊ฒฉ ํผ์ด๊ฐ ์ฒ๋ฆฌํ ์ ์๋ ๊ฒ๋ณด๋ค ๋ ๋น ๋ฅด๊ฒ ๋ฐ์ดํฐ๋ฅผ transport์ ์ฐ๊ณ ์๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น์? ๋ฐ์ดํฐ๊ฐ transport์ ๋ด๋ถ ๋ฒํผ์ ์์ ๋๋ค. ์ด๊ฒ์ด ๊ณ์ ํ์ธ๋์ง ์์ผ๋ฉด ๋ฒํผ๊ฐ ๋ฌดํ์ ์ปค์ ธ ์ฌ์ฉ ๊ฐ๋ฅํ ๋ชจ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์๋นํ ์ ์์ต๋๋ค. ์ด ๋ฌธ์ ๋ "๋ฐฑํ๋ ์ " ๋ถ์กฑ์ด๋ผ๊ณ ํฉ๋๋ค.
Asyncio๋ ์ด๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค. transport๋ ์์ฒด ๋ฒํผ ํฌ๊ธฐ๋ฅผ ๋ชจ๋ํฐ๋งํฉ๋๋ค. ๋ฒํผ๊ฐ ํน์ ์ํ์ ์ ๋์ผ๋ฉด ์ด๋ฒคํธ ๋ฃจํ๊ฐ ํ๋กํ ์ฝ์ pause_writing()
๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค. ์ด๊ฒ์ ์ ํ๋ฆฌ์ผ์ด์
์ ๋ฐ์ดํฐ ์ ์ก์ ์ค๋จํ๋ผ๋ ์ ํธ์
๋๋ค. ๋ฒํผ๊ฐ ํํ์ ์๋๋ก ๋ฐฐ์๋๋ฉด ๋ฃจํ๋ resume_writing()
์ ํธ์ถํ์ฌ ๋ค์ ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๋ ๊ฒ์ด ์์ ํจ์ ์๋ฆฝ๋๋ค.
class FlowControlledProtocol(asyncio.Protocol):
def __init__(self):
self._paused = False
self._data_source = some_data_generator() # ๋ฐ์ดํฐ ์์ค๋ผ๊ณ ์์ํด ๋ณด์ธ์
self.transport = None
def connection_made(self, transport):
self.transport = transport
self.resume_writing() # ์ฐ๊ธฐ ํ๋ก์ธ์ค๋ฅผ ์์ํฉ๋๋ค
def pause_writing(self):
# transport ๋ฒํผ๊ฐ ๊ฐ๋ ์ฐผ์ต๋๋ค.
print("Pausing writing.")
self._paused = True
def resume_writing(self):
# transport ๋ฒํผ๊ฐ ๋ฐฐ์๋์์ต๋๋ค.
print("Resuming writing.")
self._paused = False
self._write_more_data()
def _write_more_data(self):
# ์ด๊ฒ์ ์ ํ๋ฆฌ์ผ์ด์
์ ์ฐ๊ธฐ ๋ฃจํ์
๋๋ค.
while not self._paused:
try:
data = next(self._data_source)
self.transport.write(data)
except StopIteration:
self.transport.close()
break # ๋ ์ด์ ๋ณด๋ผ ๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค
# ๋ฒํผ ํฌ๊ธฐ๋ฅผ ํ์ธํ์ฌ ์ฆ์ ์ผ์ ์ค์งํด์ผ ํ๋์ง ํ์ธ
if self.transport.get_write_buffer_size() > 0:
self.pause_writing()
TCP ์ด์: ๊ธฐํ Transports
TCP๊ฐ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก์ด์ง๋ง Transport/Protocol ํจํด์ ์ด์ ๊ตญํ๋์ง ์์ต๋๋ค. Asyncio๋ ๋ค๋ฅธ ํต์ ์ ํ์ ๋ํ ์ถ์ํ๋ฅผ ์ ๊ณตํฉ๋๋ค.
- UDP: ์ฐ๊ฒฐ์ด ์๋ ํต์ ์ ๊ฒฝ์ฐ
loop.create_datagram_endpoint()
๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๊ทธ๋ฌ๋ฉดDatagramTransport
๊ฐ ์ ๊ณต๋๊ณdatagram_received(data, addr)
๋ฐerror_received(exc)
์ ๊ฐ์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌasyncio.DatagramProtocol
์ ๊ตฌํํฉ๋๋ค. - SSL/TLS: ์ํธํ๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค.
loop.create_server()
๋๋loop.create_connection()
์ssl.SSLContext
๊ฐ์ฒด๋ฅผ ์ ๋ฌํฉ๋๋ค. Asyncio๋ TLS ํธ๋์ ฐ์ดํฌ๋ฅผ ์๋์ผ๋ก ์ฒ๋ฆฌํ๊ณ ๋ณด์ transport๋ฅผ ์ป์ต๋๋ค. ํ๋กํ ์ฝ ์ฝ๋๋ฅผ ์ ํ ๋ณ๊ฒฝํ ํ์๊ฐ ์์ต๋๋ค. - Subprocesses: ํ์ค I/O ํ์ดํ๋ฅผ ํตํด ์์ ํ๋ก์ธ์ค์ ํต์ ํ๊ธฐ ์ํด
loop.subprocess_exec()
๋ฐloop.subprocess_shell()
์asyncio.SubprocessProtocol
๊ณผ ํจ๊ป ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ์์ ํ๋ก์ธ์ค๋ฅผ ์์ ํ ๋น๋๊ธฐ์ ์ด๊ณ non-blocking ๋ฐฉ์์ผ๋ก ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
์ ๋ต์ ๊ฒฐ์ : Transport vs. Streams๋ฅผ ์ฌ์ฉํด์ผ ํ๋ ๊ฒฝ์ฐ
๋ ๊ฐ์ ๊ฐ๋ ฅํ API๋ฅผ ์์ ๋กญ๊ฒ ์ฌ์ฉํ ์ ์์ผ๋ฏ๋ก ์์ ์ ์ํด ์ ํฉํ API๋ฅผ ์ ํํ๋ ๊ฒ์ด ์ฃผ์ ์ํคํ ์ฒ ๊ฒฐ์ ์ ๋๋ค. ๋ค์์ ๊ฒฐ์ ์ ๋ด๋ฆฌ๋ ๋ฐ ๋์์ด ๋๋ ๊ฐ์ด๋์ ๋๋ค.
๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ ์คํธ๋ฆผ(StreamReader
/StreamWriter
)์ ์ ํํ์ญ์์ค...
- ํ๋กํ ์ฝ์ด ๊ฐ๋จํ๊ณ ์์ฒญ-์๋ต ๊ธฐ๋ฐ์ ๋๋ค. ๋ก์ง์ด "์์ฒญ์ ์ฝ๊ณ , ์ฒ๋ฆฌํ๊ณ , ์๋ต์ ์ฐ๋ ๊ฒ"์ด๋ผ๋ฉด ์คํธ๋ฆผ์ด ์๋ฒฝํฉ๋๋ค.
- ์ ์๋ ค์ง ๋ผ์ธ ๊ธฐ๋ฐ ๋๋ ๊ณ ์ ๊ธธ์ด ๋ฉ์์ง ํ๋กํ ์ฝ์ ๋ํ ํด๋ผ์ด์ธํธ๋ฅผ ๊ตฌ์ถํ๊ณ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, Redis ์๋ฒ ๋๋ ๊ฐ๋จํ FTP ์๋ฒ์ ์ํธ ์์ฉํ๋ ๊ฒฝ์ฐ์ ๋๋ค.
- ์ฝ๋ ๊ฐ๋
์ฑ ๋ฐ ์ ํ์ , ๋ช
๋ นํ ์คํ์ผ์ ์ฐ์ ์ํฉ๋๋ค. ์คํธ๋ฆผ์ ์ฌ์ฉํ
async/await
๊ตฌ๋ฌธ์ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ์ฒ์ ์ ํ๋ ๊ฐ๋ฐ์๊ฐ ์ดํดํ๊ธฐ ๋ ์ฌ์ด ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. - ์ ์ํ ํ๋กํ ํ์ ์ ์์ด ํต์ฌ์ ๋๋ค. ๋ช ์ค์ ์ฝ๋๋ง์ผ๋ก ์คํธ๋ฆผ์ ์ฌ์ฉํ์ฌ ๊ฐ๋จํ ํด๋ผ์ด์ธํธ ๋๋ ์๋ฒ๋ฅผ ๊ฐ๋ํ๊ณ ์คํํ ์ ์์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ Transport ๋ฐ Protocol์ ์ ํํ์ญ์์ค...
- ์ฒ์๋ถํฐ ๋ณต์กํ๊ฑฐ๋ ์ฌ์ฉ์ ์ง์ ๋คํธ์ํฌ ํ๋กํ ์ฝ์ ๊ตฌํํ๊ณ ์์ต๋๋ค. ์ด๊ฒ์ด ์ฃผ์ ์ฌ์ฉ ์ฌ๋ก์ ๋๋ค. ๊ฒ์, ๊ธ์ต ๋ฐ์ดํฐ ํผ๋, IoT ์ฅ์น ๋๋ P2P ์ ํ๋ฆฌ์ผ์ด์ ์ฉ ํ๋กํ ์ฝ์ ์๊ฐํด ๋ณด์ญ์์ค.
- ํ๋กํ ์ฝ์ด ๋งค์ฐ ์ด๋ฒคํธ ์ค์ฌ์ ์ด๊ณ ์์ํ๊ฒ ์์ฒญ-์๋ต ๋ฐฉ์์ด ์๋๋๋ค. ์๋ฒ๊ฐ ์ธ์ ๋ ์ง ํด๋ผ์ด์ธํธ์ ์๊ธฐ์น ์์ ๋ฉ์์ง๋ฅผ ๋ณด๋ผ ์ ์๋ ๊ฒฝ์ฐ ํ๋กํ ์ฝ์ ์ฝ๋ฐฑ ๊ธฐ๋ฐ ํน์ฑ์ด ๋ ์์ฐ์ค๋ฝ๊ฒ ์ ํฉํฉ๋๋ค.
- ์ต๋ ์ฑ๋ฅ๊ณผ ์ต์ ์ค๋ฒํค๋๊ฐ ํ์ํฉ๋๋ค. ํ๋กํ ์ฝ์ ์คํธ๋ฆผ API์ ๊ด๋ จ๋ ์ผ๋ถ ์ค๋ฒํค๋๋ฅผ ์ฐํํ์ฌ ์ด๋ฒคํธ ๋ฃจํ์ ๋ ์ง์ ์ ์ธ ๊ฒฝ๋ก๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ์ฐ๊ฒฐ์ ๋ํ ์ธ๋ฐํ ์ ์ด๊ฐ ํ์ํฉ๋๋ค. ์ฌ๊ธฐ์๋ ์๋ ๋ฒํผ ๊ด๋ฆฌ, ๋ช
์์ ํ๋ฆ ์ ์ด(
pause/resume_writing
) ๋ฐ ์ฐ๊ฒฐ ์๋ช ์ฃผ๊ธฐ์ ๋ํ ์์ธํ ์ฒ๋ฆฌ๊ฐ ํฌํจ๋ฉ๋๋ค. - ๋คํธ์ํฌ ํ๋ ์์ํฌ ๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ตฌ์ถํ๊ณ ์์ต๋๋ค. ๋ค๋ฅธ ๊ฐ๋ฐ์์๊ฒ ๋๊ตฌ๋ฅผ ์ ๊ณตํ๋ ๊ฒฝ์ฐ Protocol/Transport API์ ๊ฐ๋ ฅํ๊ณ ์ ์ฐํ ํน์ฑ์ด ์ข ์ข ์ฌ๋ฐ๋ฅธ ๊ธฐ๋ฐ์ ๋๋ค.
๊ฒฐ๋ก : Asyncio์ ๊ธฐ๋ฐ์ ํฌ์ฉ
Python์ asyncio
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๊ณ์ธต์ ๋์์ธ์ ๊ฑธ์์
๋๋ค. ๊ณ ์์ค ์คํธ๋ฆผ API๋ ์ ๊ทผ ๊ฐ๋ฅํ๊ณ ์์ฐ์ ์ธ ์ง์
์ ์ ์ ๊ณตํ๋ ๋ฐ๋ฉด, asyncio์ ๋คํธ์ํน ๊ธฐ๋ฅ์ ์ง์ ํ ๊ฐ๋ ฅํ ๊ธฐ๋ฐ์ ๋ํ๋ด๋ ๊ฒ์ ์ ์์ค Transport ๋ฐ Protocol API์
๋๋ค. I/O ๋ฉ์ปค๋์ฆ(Transport)์ ์ ํ๋ฆฌ์ผ์ด์
๋ก์ง(Protocol)๊ณผ ๋ถ๋ฆฌํ์ฌ ์ ๊ตํ ๋คํธ์ํฌ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ถํ๊ธฐ ์ํ ๊ฐ๋ ฅํ๊ณ ํ์ฅ ๊ฐ๋ฅํ๋ฉฐ ๋๋๋๋ก ์ ์ฐํ ๋ชจ๋ธ์ ์ ๊ณตํฉ๋๋ค.
์ด ์ ์์ค ์ถ์ํ๋ฅผ ์ดํดํ๋ ๊ฒ์ ๋จ์ํ ํ๋ฌธ์ ํ๋ จ์ด ์๋๋๋ค. ๊ฐ๋จํ ํด๋ผ์ด์ธํธ์ ์๋ฒ๋ฅผ ๋์ด ์ค ์ ์๋๋ก ์ง์ํ๋ ์ค์ง์ ์ธ ๊ธฐ์ ์ ๋๋ค. ์ด๋ค ๋คํธ์ํฌ ํ๋กํ ์ฝ์ด๋ผ๋ ํด๊ฒฐํ ์ ์๋ ์์ ๊ฐ์ ์ฃผ๊ณ , ์๋ฐ ์์์ ์ฑ๋ฅ์ ์ต์ ํํ ์ ์๋ ์ ์ด๋ ฅ์ ์ ๊ณตํ๋ฉฐ, Python์์ ์ฐจ์ธ๋ ๊ณ ์ฑ๋ฅ, ๋น๋๊ธฐ ์๋น์ค๋ฅผ ๊ตฌ์ถํ ์ ์๋ ๋ฅ๋ ฅ์ ์ ๊ณตํฉ๋๋ค. ๋ค์์ ์ด๋ ค์ด ๋คํธ์ํน ๋ฌธ์ ์ ์ง๋ฉดํ๊ฒ ๋๋ฉด ํ๋ฉด ๋ฐ๋ก ์๋์ ์๋ ๊ฐ๋ ฅํจ์ ๊ธฐ์ตํ๊ณ Transport ๋ฐ Protocol์ ์ฐ์ํ ๋์ค๋ฅผ ์ฃผ์ ํ์ง ๋ง๊ณ ํ์ฉํ์ญ์์ค.