사용자 삽입 이미지



일본어 버전과 한국어 버전입니다.
하레와 구우의 오프닝 러브 트로피카나!!





[한국어 버전 오프닝] 러브 트로피카나


보아라 사랑에 고픈 소년들아

보아라 사랑을 나눌 소녀들아

청춘의 환상과 정열 가득모아


정글은 언제나 맑은 뒤 흐림!


아찔하게 돌리는 허리무초

아이들은 잠잘 때 아미고

키스하면 너에게 빠질 것 같고

사랑을 빤히 불태울 tonight (오예~)


날 보는 눈길 받았다면

내 모든 사랑 담아 going

기분이 정말 좋아지네

아침이 올 때까지 dancing

love love love 트로피카나


첫눈에 가슴이 떨림 처음인걸

명심해 넌 이제 내가 콕 찍은걸

미안해 이 순간 나의 포로란 걸

정글은 언제나 맑은 뒤 흐림 (우!)


보아라 사랑에 고픈 소년들아

보아라 사랑을 나눌 소녀들아

청춘의 환상과 정열 가득모아


정글은 언제나 맑은 뒤 흐림!



 

[일본어 버전 오프닝] 러브 트로피카나


 

グウ! < 구우! >
구우!

戀(こい)せよ 少年少女(しょうねんしょうじょ)たち
사랑하라 소년소녀들이여
코이세요 쇼우네-응 쇼우죠따찌

きらり 瞳(ひとみ)に ほしいれて
반짝이고 눈동자에 별을 담아
키라리 히또미니 호시이레떼

生(う)まれたまんまのジ-ョネツか
태어난 그대로의 정렬이
우마레따만마노 죠네쯔카

火花(ひはな)ちらす JUNGLE ハレのちグウ
불꽃 튀기는 정글 하레 and 구우
히바나찌라스 JUNGLE 하레노찌구우

めくるめく腰(こし)つき ム-チョ
현란한 몸짓 무-쵸
메쿠루메구코시쯔키 무-쵸

子供(こども)にゃきわどい アミ-ゴ
아이들에겐 아슬하기만 한 아미고
코도모냐 키와도이 아미-고

キスしたら吸(す)いこまれそう
Kiss를 하면 빠져들 것만 같아
키스시따라케이코마레소우

怖(こわ)いもの見(み)たさTonight
무서운 걸 보았는 건 Tonight
코와이모노미다사Tonight

怖(お)じ氣(け)ついたら ダメ
겁을 먹거나 해서는 안돼
오지케쯔이따라 다메

押(お)して押(お)されて Going
밀거니 당기거니 Going
오시떼오사레떼 Going

ドシキリ 氣分(きぶん)がい-ね
그냥 기분이 좋은걸
돗-끼리 키부은가 이-네

ちゃっかり朝(あさ)まで Danc`n
꼬박 아침까지 Dancing
&#52339;카리아사마데 Danc`n

LOVE LOVE LOVE
LOVE LOVE LOVE
LOVE LOVE LOVE

トロビカ-ナ
토로비카나
토로비까-나

ヤシの木陰(こかげ)てつかまえて
야자나무 그늘에서 붙잡고서
야시노 코까게떼 쯔카마에떼

じらしてとことんとことん
속을 다 태워먹고 기어이 마지막까지
지라시떼도코도콘도코돈

ごめんね あなたはもう虜(どりこ)
미안해요 당신도 이미 노예
고멘-네 아나따와 모우도리꼬

逃(に)げられないJUNGIE ハレのちグウ
도망칠 수 없는 정글 하레 and 구우
니게라레나이 JUNGIE 하레노치구우

ゆうはくぼをせんで ム-チョ
용기는 성장의 선인 무-쵸
유우와쿠보오세은데 무-쵸

たいようの せいだわ アミ-ゴ
태양의 성대함은 아미고
타이요오노 세이다와 아미-고

おんなのこは たるしじゃない
여자아이들은 나른하지 않고
오은나노꼬와 다루시쟈나이

まものが はんぶん ふぃふぃ
마귀는 떠든다 휘휘
마모노가 한부은- 휘휘

ぶぎれだのしい OK
이상한것이라도 OK
부기레다노시이 OK

じょくりこわいは ムんライ
모든 것이 두려운 문-라이
죠쿠리코와이와 문-라이

ごなのついまで Kisssing
바로 조금만 있으면 Kisssing
고나노쯔이마데 Kisssing

ぱぱやぱぱやDanc`n
빠빠야빠빠야 Dancing
빠빠야빠빠야 Danc`n

LOVE LOVE LOVE
LOVE LOVE LOVE
LOVE LOVE LOVE

トロビカ-ナ
토로비카나
토로비까-나

戀(こい)せよ 少年少女(しょうねんしうょじょ)たち
사랑하라 소년소녀들이여
코이세요 쇼우네-응 쇼우죠따찌

きらり 瞳(ひとみ)に ほしいれて
반짝이고 눈동자에 별을 담아
키라리 히또미니 호시이레떼

生(う)まれたまんまのジ-ョネツか
< 태어난 그대로의 정렬이 >
우마레따만마노 죠네츠카

火花(ひはな)ちらす JUNGLE ハレのちグウ
불꽃 튀기는 정글 하레 and 구우
히바나찌라스 JUNGLE 하레노찌구우

のみこまれて みたい ム-チョ
곤란한 것을 보면은 무-쵸
노미코마레떼 미따이 무-쵸

めもくらむせかい アミ-ゴ
현혹되는 세계 아미고
메모쿠라무세카이 아미-고

みたことも ないこい だから
보는 아이들도 어이없다 그래서
미따코또모 나이코이 다까라

ドキドキが くせんの Tonight
두근거림이 고전되 Tonight
도키도키가 쿠센-노 Tonight

モジモジしてたら ダメ
머뭇머뭇 거리면 안돼
모지모지시떼따라 다메

きによのきょしょうむな
신경쓰지 말고 웃어
키니요노쿄쇼우무나

あまいいかずに ユウナ
달콤한 酒에 ユウナ
아마이이카즈니 유우나

ふたりでかれて Danc`n
그남자와 둘이서 Dancing
후따리데카레떼 Danc`n

LOVE LOVE LOVE
LOVE LOVE LOVE
LOVE LOVE LOVE

トロビカ-ナ
토로비카나
토로비까-나

戀(こい)せよ 少年少女(しょうねんしょうじょ)たち
사랑하라 소년소녀들이여
코이세요 쇼우네-응 쇼우죠따찌

きらり 瞳(ひとみ)に ほしいれて
반짝이고 눈동자에 별을 담아
키라리 히또미니 호시이레떼

生(う)まれたまんまのジ-ョネツか
태어난 그대로의 정렬이
우마레따만마노 죠네쯔카

火花(ひはな)ちらす JUNGLE ハレのちグウ
불꽃 튀기는 정글 하레 and 구우
히바나찌라스 JUNGLE 하레노찌구우

ヤシの木陰(こかげ)てつかまえて
야자나무 그늘에서 붙잡고서
야시노 코까게떼 쯔카마에떼

じらしてとことんとことん
속을 다 태워먹고 기어이 마지막까지
지라시떼도코도콘도코돈

ごめんね あなたはもう虜(どりこ)
미안해요 당신도 이미 노예
고멘-네 아나따와 모우도리꼬

逃(に)げられないJUNGIE ハレのちグウ
도망칠 수 없는 정글 하레 and 구우
니게라레나이 JUNGIE 하레노치구우

戀(こい)せよ 少年少女(しょうねんしょうじょ)たち
사랑하라 소년소녀들이여
코이세요 쇼우네-응 쇼우죠따찌

きりい 瞳(ひとみ)に ほしいれて
반짝이고 눈동자에 별을 담아
키라리 히또미니 호시이레떼

生(う)まれたまんまのジ-ョネツか
태어난 그대로의 정렬이
우마레따만마노 죠네쯔카

火花(ひはな)ちらす JUNGLE ハレのちグウ
불꽃 튀기는 정글 하레 and 구우
히바나찌라스 JUNGLE 하레노찌구우 


 

2007/09/17 19:11 2007/09/17 19:11

사용자 삽입 이미지




사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지




너무너무 좋아하는 애니메이션이다~~~
우리나라에 "정글은 언제나 맑음 뒤 흐림" 이라는 제목으로 애니메이션이 방송도 되고
박혜경이 노래도 불러주고 하기도 했던 애니~~~
구루미 넘 이뿌다 ㅋㅋ









아래 설명글은 네이버 지식인에서 스크랩하였습니다.
[원문] http://kin.naver.com/open100/db_detail.php?d1id=3&dir_id=305&eid=NKXsV0U5Sih5umAGFYQkHqbKFFkEdCLY&qb=x8+3uSDBpLHb


C#1) 하레 (화니)


상당히 낙천적임. 그러나 자신보다 더 낙천적인 엄마를 돌보느라 정신없음. 게다가 구우까지 합세한 이후로는 이름과는 어울리지 않게 점점 어두운 인생이 되어가고 있음. 비디오 게임 매니아. 랩퍼기질 보유. 필살기는 비오는 날 궁상떨기.


이름이 하레인데, 이는 "맑음"을 뜻합니다. 정글에서 엄마인 웨다와 단 둘이 살아가고 있던 어느 날, 바나나를 따오는 심부름을 수행하던 중 정체를 알 수 없는 무언가를 발견하고 혼비백산해 버립니다. 그러나... 그의 말을 정글 사람들은 무시하죠. 이게 그의 '인생의 카오스'의 신호탄이 되어버렸습니다.

그날 저녁. 술에 거나하게 취한 웨다가 예쁘장한 소녀를 데려오게 됩니다. 그 이름하여 '구우'. 뽀얀 피부에 귀여운 외모. 확실히 정글에서 살던 사람이 아닌 것 같은 분위기에 하레는 사랑의 감정을 키웁니다. 그러나 다음날 아침에 맛보게 된 절규. 그 이후로 그의 인생은 구우로 인해 꼬이게 됩니다.

그의 탄생이 상당히 문제가 많았었는지 엄마인 웨다는 집을 나와 정글에서 하레를 홀로 낳아 키웁니다. 그러나 이런 배경들과는 반대로 성격은 상당히 낙천적입니다. 그러나... 웨다는 하레의 낙천적인 성격을 한단계 더 뛰어넘는 정도라서 그런 엄마를 돌보느라 정신이 없죠. 구우가 합세한 이후로 더더욱 정신없는 나날들을 보냅니다.

정글에 비디오 게임기가 조금은 안어울리지만... 상당히 매니아입니다. 왠만한 게임은 다 마스터한듯... 나중에 만나는 뱅크로버들과 비디오 게임에 대해 열변을 토하는 것을 보면 상당한 수준인 듯 보입니다.

랩퍼기질을 보유한 듯 속사포처럼 내뱉는 대사들이 인상적입니다. 이 역시 한국어 더빙판도 굉장히 좋았습니다. 하레 성우 맡으신 이명선님 좋아하는 성우분들 중 한분이셔서 더 좋았었죠...


C#2) 구우 (구루미)

한마디로 표현해서 "엽기". 안면근육의 수축성이 굉장한듯 영업용 얼굴과 일반 얼굴의 자유로운 표현 가능. 소화기관이 우수한듯 무엇이든지 먹고 보자는 마인드를 지님. 뱃속에 새로운 세계가 펼쳐져 있음. 어디서 왔는지, 정체가 무엇인지 알 수 없음. 가끔씩 성인 여성의 모습으로 변하는 것 같기도 함. 하레를 가지고 노는것을 즐기는 듯. 필살기는 자신의 의사를 최소한의 언어와 감탄사로 해결하는 뛰어난 함축성. 상당히 머릿속을 울리게 만드는 웃음.


이름이 구우인데, 이는 "흐림"을 뜻합니다. 이름 자체가 하레의 맑고 창창한 인생을 흐리게 만들어 버리겠다는 의지를 담고 있습니다. 어느 날, 어디에서 왔는지 모르지만 아무튼 하레 앞에 나타난 그녀. 처음엔 뛰어난 안면 위장술로 하레의 환심을 불러일으켰습니다. 그러나 다음날... 그 귀여운 얼굴은 어딜가고 얼굴에 어둠이 가득한채 상대방을 시종일관 야려보는 듯한 본래의 얼굴에 하레는 절규하게 됩니다.

안면근육의 수축성이 뛰어남도 모자라 소화기관도 굉장히 뛰어난지 뭐든지 눈에 보이면 무조건 먹고 보자는 마인드를 가지고 있습니다.

그러나... 소화기관의 우수성에도 불구하고 소화능력은 상당히 떨어지는지 삼킨것을 소화하지 못한 채(안한다고 볼 수도 있겠죠...) 뱃속에 그대로 간직하고 있습니다. 그렇게 쌓이고 쌓여서 산이 형성되고, 들판이 펼쳐지고, 바다도 만들어지고, 사람들도 살아가고, 다리 여럿달린 이상한 고양이도 돌아다니고, 팬더가 음악 레코드 스크래치도 하면서 재주부리고... 아무튼 또다른 세계를 창조해내고 말았습니다. 가끔씩 하레가 가면 구우 뱃속에 사는 사람들이 굉장히 반겨주기도 하죠.

하레를 가지고 노는것을 즐깁니다. 하레가 "이렇게 되었으면 좋겠다"고 생각하면 그 생각이 이루어 지게끔 해줍니다. 단... 의도는 좋지만 그 과정이 상당히 불순하다는데 문제가 있죠. 이렇게 해서 생긴 문제들을 해결해가면서 하레의 궁상은 그 정도가 심해집니다.

하레의 속사포처럼 내뱉는 대사들의 향연과는 반대로 구우는 자신의 의사를 최소한의 언어와 약간 허스키한 보이스의 감탄사들로 전달합니다. 아마도 시인의 기질을 가지고 있는 듯 합니다. 특히 그녀의 의사전달에 있어서 최고의 결정체는 바로 웃음. 안면근육의 움직임을 최소화한 상태에서 턱관절을 마음대로 사용하는 그 스킬... 인상적입니다.

한국어 더빙판에서 구우 목소리 하셨던 여민정님... 이 애니메이션을 보고 나서 존경하게 되었습니다... 와타나베 나오코님도 정말 대단하셨죠...


C#3) 웨다

낙천적이다 못해 철이 없음. 애주가. 범가죽무늬의 옷이 상당히 인상적. 집안일 내공 0. 오직 할줄 아는 것은 새우 그라탕 만들기밖에 없음. 그나마 이것도 잘 안함.


성격이 낙천적이다 못해 철이 없는 어린애같은 모습을 자주 보입니다. 애주가라서 매일 술을 입에 달고 다닙니다. 그러니 집안일에 신경 쓸 겨를이 없겠죠... 유일하게 잘하는 것이라곤 새우 그라탕 요리를 하는 것 뿐인데... 이것도 하는 모습 제대로 못봤습니다.

어렸을 때는 도시에서 자랐습니다. 그녀의 집안이 상당한 부유층이었던지 후에 등장하는 그녀의 집이 굉장히 으리으리하더군요.

그녀의 주치의였던 크라이브와의 부적절한 관계 속에 하레를 낳았다고 전해지고 있지만... 진실은 아마도 그녀만이 알고 있을 것 같군요.


C#4) 크라이브
변태양호선생 ← 이걸로 모든 설명 가능. 백발로 인해 이발사인 다마로부터 공포의 나날들을 겪게됨. 하레가 아들이라는 사실 인정 안함.(하레 역시 크라이브를 아버지라고 생각하지 않음) 어린 아들의 생일날 도색잡지를 선물해주는 개방성 보유. 남자와 여자를 대하는 태도가 완전히 다름.(하레를 여자아이인줄 알고 대하던 태도와 남자임이 밝혀진 뒤 대하던 태도를 통해 확실한 비교 가능)

도시에서 정글 학교 양호 선생님으로 부임하면서 등장하는 캐릭터입니다. 머리가 백발인데, 나중에 이발사인 다마로부터 공포의 나날들을 겪기도 합니다. 하레로부터 변태양호선생이라는 칭호를 하사(?)받았는데, 이 칭호에 그의 성격이 모두 압축되어 있습니다. 나중에 웨다로부터 자신이 하레의 아버지라는 사실을 통보받지만, 하레를 아들이라고 생각하지 않는듯 합니다. 하레 역시 전혀 아버지다운 행동을 보여주지 않는 크라이브를 보고 아버지라고 생각하지 않죠... 하지만 중간에 서로의 몸이 바뀐 이후로 조금씩 이해해 나가는 방향으로 갈 듯 하다가 결국... 크라이브의 계략(?)으로 하레는 몰매를 맞으며 또다시 궁상에 빠지고 맙니다.


C#5) 촌장님

가슴털. 구우사마의 전설. ← 역시 이걸로 모든 설명 가능. 포크테 매니아. 토포스테의 할아버지.


레게파마용 가발을 만들 수 있을 정도의 가슴털... 그리고 그 가슴털을 잃어버린 뒤 미라처럼 살아가다가 결국 구우사마의 전설을 남긴 캐릭터... 촌장님이 구우를 바라보며 "구우사마"라고 외칠때... 감동 그 자체였습니다. 살아있는 눈빛연기... 이제는 전설이 되었습니다.


C#6) 정글 학교 패밀리

# 절대숙면. 잠神 - 레지 선생님 ; 마리의 오빠이면서 정글 학교의 선생님. 밤에 무엇을 그렇게 하는지 아침과 낮에는 항상 잠만 자고 있음. 수업은 항상 두가지 패턴 → 자습 or 낮잠.


# 대사의 9할이 웃음 - 와지 ; 구우의 의사 표현 결정체인 웃음을 가르쳐준 장본인. 등장할 때 마다 거의 웃는것밖에 못봤음.(무슨 동물의 혼령때문에 이렇게 되었다고 하던데 기억이 잘 안나는군요)

# 반신탈의 - 굽타 & 토포스테 ; 토포스테는 촌장님의 손자이며 굽타는 자칭 정글의 "짱"으로 둘 다 반신을 탈의한 상태로 정글을 싸돌아다님. 토포스테는 촌장님에 대한 사랑이 대단한듯. 위로 솟구친 머리가 인상적. 굽타는 다혈질에 희한하게 변하는 머리색이 인상적.


# 크라이브는 나의 적 - 위구르 ; 웨다를 상당히 짝사랑하고 있는 듯. 웨다 일이라면 눈에 불을 켜고 다닌다. 그 외에는 상당히 정상적인 캐릭터.


# 동정심 유발 9단 - 마리 ; 오빠인 레지 선생님과 정글 학교에서 숙식을 함. 상당히 귀여운 외모에 하레를 굉장히 좋아하는 듯 가끔씩 그와의 결혼생활을 상상하기도 함. 웨다도 좋아하는지 가끔씩 하레를 보며 "하레는 엄마가 있어서 좋겠다" 필살기 사용.


# 무슨 생각하는지 알수 없음 - 라벤나 ; 가장 정상적인 캐릭터. 반대로 말하면 별다른 특이점이 없는 캐릭터이기도 함.


# 말이 적어서 오히려 기억나네 - 라이아 ; 연두색 갈래머리. 머뭇거리는 말투. 말하는거 한번도 못봤음. (남자아이도 있었는데 생각이 잘 안나네요 ^^;;;)

C#7) 웨다의 메이드


# 웨다라면 만사 제쳐두고 달려드는 무서운 메이드. 쌍코피의 전설 - 벨 ; 도시에서 온 웨다의 메이드로 웨다를 다시 도시로 데려가려는 목적을 가지고 정글로 옴. 웨다에 대해서는 거의 크라이브에 대한 다마 수준으로 집착이 대단함. 웨다 생각에 쌍코피를 쏟는 것이 인상적. 곁에 같이 있는 아시오를 언제나 샌드백으로 이용하고 있음.


# 첫 등장이 관 속이네 - 아시오 ; 웨다의 메이드 역할을 하지만 사실은 웨다의 소꿉친구였던 그. 웨다와 하레 일이라면 목욕하던 도중에도 뛰쳐나온다. 얼굴이 상당히 그늘져 있음. 그러나 마음씨 하나는 착하고 배려심이 깊은 캐릭터.


C#8) 정글 패밀리
# 울트라 러브러브 닭살의 극치 - 체트 & 아디(아리?) ; 정글 곳곳에 게릴라처럼 나타나 부부싸움 하다가도 체트의 닭살 멘트 하나면 다시 CF찍고 있는 그들. 정글 내에서 싸움 빈도수가 제일 많을 듯.

# 포크테 전설 - 레베카 ; 웨다의 친구로 역시 애주가. 포크테 전설의 실제 주인공이기도 함. 정말 포크테가 그녀를 길렀는지는 알 수 없지만... 가능성이 충분히 있음.


# 입맛 달아날 것 같은 식용 생물 - 포크테 ; 정글 주변에 언제나 포크테 몇마리씩은 꼭 있을 정도로 이 애니메이션의 마스코트 역할을 하기도 함. 식용이라고 하는데... 입맛 달아날 것 같음. 포크테 전설이 있는 것으로 보아 양육의 능력을 갖추고 있을 것으로 보임.


# 영감의 추억 - 다마 ; 국내에서는 까꾸미러(?) 였던걸로 알고있음. 머리가 거의 촌장님 가슴털 수준. 오직 죽은 할아버지가 백발이라는 것만 생각하고 백발이면 무조건 달려듬. ← 그 최대의 희생양 : 크라이브

# 검고 딱딱하고 울퉁불퉁하고 냄새나고... - 반달곰 ; 반달곰에 대한 설명은 너무 길어서 다 기억나지도 않을 정도. 정글 사람들에게 상당한 공포심을 일으켰음. 결국 구우와의 K-1 매치에서 지고 말았지만 다마와 싸운다면 거의 대등할듯.


C#9) 도시 패밀리

# 나 외에는 모두 적 - 로버트 ; 경호 정신이 투철하다고 봐야 할 바디가드. 벨을 상당히 존경하는 듯... 뱅크로버 사건 이후에 성격이 약간 변한 모습을 보여주기도 함.


# 웨다의 엄마 - 샤론 ; 하레와 우연히 만나게 된 할머니로, 나중에 웨다의 엄마임이 밝혀짐. 하레의 노력에도 불구하고 웨다와의 상봉이 어려워 질 듯 했다가 결국 막판에 웨다를 만남으로써 깔끔하게 마무리.


도시에서 일어난 일들 중에 뱅크로버 사건도 기억나는군요. 특히 하레와 게임에 대해 열변을 토한 그 대머리...


C#10) 구우의 뱃속 패밀리

# 어서와 하레~^^ - 토모요 ; 구우의 뱃속에 사는 여자로 하레가 구우의 뱃속으로 놀러오면 언제나 반겨줌. 아직도 왜 거기에서 계속 살고있는지 의문.


# 풍기위원장 -.-;; - 세이이치 ; "풍기위원장"이라고 새겨진 완장을 차고 있는 고등학생. 아마도 구우 뱃속세계의 음양을 조화롭게 하기 위한 목적으로 살고 있는 듯.


# 나 돌아갈래 - 야마다 ; 직장 상사에게 차인 뒤 바다에 투신했다가 구우가 바닷물을 삼킬 때 같이 구우의 뱃속으로 딸려 들어갔을 것으로 추정. 성격이 상당히 극과 극을 오감. 나중에 구우의 뱃속에 완벽히 적응된 모습을 보여줌.


그 외에도 다리 여럿 달린 겁많은 고양이와 음악 레코드를 스크래치하던 팬더가 생각나는군요... 完

2007/09/17 18:57 2007/09/17 18:57

플래쉬 게임 사이트

노트/유머 2007/09/17 16:47 posted by zekill

http://www.onlinegamesquad.com/index.php


플래쉬 게임 많이 있습니답~~

아 글고 음...머라 해야대나...
스타크에 유즈맵세팅 보면 있는 무한으로 나오는 적 없애기던가 그거와 유사한....
예전에 정과장님이 열심히 빠지셨던...ㅋ

할튼 시간죽이기 좋은 겜하나 소개~~~

http://novelconcepts.co.uk/

or

http://www.onlinegamesquad.com/index.php?1085-1

2007/09/17 16:47 2007/09/17 16:47

IOCP- 윈속 프로그래밍

출처 :  http://www.winapiprogramming.com/

이 글은 제가 얼마 전에 프로그램 세계에 연재했던 글입니다.
다음 3회 연재 글 중에서 마지막 회에 해당합니다. 1,2회에 해당하는 글은 이 책에서 찾아보실 수 있습니다.

  • 2002/2 - 1. 윈속이란 ? - 간단한 에코우 서버/클라이언트 프로그램 만들기
  • 2002/4 - 2. 멀티스레드 윈속 서버 프로그램으로 업그레이드 하기
  • 2002/5 - 3. IOCP 윈속 서버 프로그램

    이번 회에는 지난 회에서 멀티스레드 윈속 서버 프로그램을 IOCP(Input Output Completion Port)를 이용하는 것으로 변경해보도록 하자. 전에 서버 프로그래밍에 관한 필자의 연재기사에서 수차례 IOCP를 언급한 바 있었는데 이제서야 설명을 하게 되었다.

    지난 회에 만들어본 멀티스레드 윈속 서버 프로그램의 문제점은 사용자의 수가 많아지면 스레드의 동적 생성과 스레드간의 잦은 컨텍스트 스위칭으로 인한 오버헤드가 크다는 점이었다. 이러한 점을 극복하기 위해 도입된 것이 바로 IOCP이다. 방금 설명한 것처럼 이는 멀티스레드 프로그래밍에서 유용하게 사용할 수 있으며 그 중에서도 소켓이나 파일, 메일슬롯, 파이프와 같은 입출력 관련 프로그램에서 유용하게 사용할 수 있다.

    필자는 IOCP를 파일 I/O가 많은 응용프로그램과 네트웍 I/O가 많은 윈속 프로그램에서 사용해봤는데 그냥 단순한 멀티스레드 프로그램을 작성하는 것보다 괜찮은 성능을 가짐을 알 수 있었다. 부하가 그리 크지 않다면 IOCP를 사용하나 사용하지 않으나 성능상에 큰 차이가 없다. 하지만 부하가 클 경우에는 (예를 들어 윈속 서버 프로그램이라면 현재 접속 사용자수가 많을 경우에는) 상당한 차이를 가져온다는 점을 잘 새겨두기 바란다. 하지만 파일 I/O가 아주 빈번한 응용프로그램에서는 IOCP를 사용한 멀티스레드 프로그램이나 그냥 멀티스레드 프로그램이나 성능에 있어 별 차이가 없다. 그 이유는 스레드로 인한 오버헤드보다 파일 I/O 자체로 인한 오버헤드가 더 크기 때문이었다.

    단, IOCP가 무슨 마법처럼 시스템이 가진 하드웨어 제약조건 이상으로 많은 수의 사용자를 처리할 수 있도록 해주거나 하는 것은 아니란 점을 명심하기 바란다. 부하가 많은 시점에 그냥 멀티스레드 프로그래밍을 하는 것보다 더 좋은 성능을 보일 뿐이다. 획기적으로 좋은 성능을 보이거나 하는 마술과 같은 것은 아니란 것이다. 또한 IOCP는 NT 4.0, 2000, XP에서만 사용가능하다는 점도 알아두기 바란다.

    먼저 IOCP라는 것이 그리 이해하기 쉬운 편은 아니고 이해해서 사용하기는 더욱 어렵다는 점을 밝히고 싶다. 겁먹으라고 하는 소리는 아니고 잘 이해가 안되어도 필자 탓을 하거나 자신의 머리탓(?)을 하지말고 한번 더 읽어보라는 의미에서 하는 말이다. 참고문헌 2>와 3>에 필자가 처음 IOCP를 공부할 때 봤던 책과 인터넷 기사를 적어두었다. 참고하기 바란다. 또, 마이크로소프트 플랫폼 SDK의 예제 프로그램 중에 보면 윈속에서 IOCP를 어떻게 사용할 수 있는지 보여주는 간단한 예가 있다. 참고문헌 4에 적었다. 사실 이번 연재에서 작성한 서버 예제 프로그램도 이 것을 바탕으로 작성되었다. 클라이언트 예제 프로그램은 사실 지난 회와 동일하다. 그렇기 때문에 클라이언트 프로그램에 대해서는 다루지 않겠다.

    1. IOCP의 필요성 ?

    IOCP가 왜 필요한지 알아보려면 기존 멀티스레드 프로그래밍의 제한점을 먼저 이해해야 한다.

    많은 수의 스레드 생성으로 인한 오버헤드 : 확장성의 제한

    동시에 여러 사용자를 처리할 수 없는 프로그램을 서버 프로그램이라고 부를 수 없을 것이다. 서버 프로그램이 되려면 동시에 여러 사용자로부터의 요구를 처리할 수 있어야 하고 그렇게 하기 위해서 스레드를 사용할 수 밖에 없다. 결론적으로 진정한 다중 사용자용 서버 프로그램을 짜본 사람이라면 동시 사용자 처리를 위해 누구나 스레드를 사용하고 있을 것이다. 대부분의 경우 지난 회에 살펴본 예제 프로그램처럼 현재 접속 중인 사용자의 수만큼 스레드를 만드는 방식을 취하게 된다. 즉 사용자마다 그 요구를 처리하기 위한 전담 스레드를 생성하는 것이다.

    하지만 이 방식의 문제점 중의 하나는 바로 현재 접속 중인 사용자의 수가 늘어날 경우에 발생한다. 스레드의 생성은 당연히 자원의 사용을 가져온다. 어느 수 이상으로 스레드가 생성되면 프로그램의 성능이 오히려 전체적으로 저하된다. 이유는 너무 많은 스레드가 생성되면 아무래도 그로 인해 자원이 많이 필요하게 되고 또 그 많은 스레드들간의 컨텍스트 스위칭으로 인해 실제 CPU가 어떤 일을 하는 시간보다 컨텍스트 스위칭하는데 상당한 시간을 보내게 되기 때문이다. 예를 들어 CPU의 수보다 스레드의 수가 많다면 사실 스레드간의 컨텍스트 스위칭으로 인한 오버헤드가 있다고 볼 수 있다. (사실 CPU의 수만큼 스레드의 수가 존재하는 것이 이상적이지만 이는 사실상 불가능한 일이다. 이는 만들고자 하는 응용프로그램의 특성에 따라 굉장히 달라질 수 있다.)

    IOCP는 이러한 단점을 극복하기 위해 하나의 스레드가 하나 이상의 사용자로부터의 요구를 처리할 수 있도록 해준다. 그렇다고 하나의 스레드만을 생성하는 것은 아니다. 여러 개의 스레드를 생성하지만 한 스레드가 한 사용자만을 전담하는 방식은 아니라는 것이다. 즉, 실행되는 스레드의 수를 적게 해서 이로 인한 컨텍스트 스위칭의 수를 줄이는 것이다. 이것이 가능하려면 이제 뒤에서 살펴볼 것처럼 프로그램내에서 I/O시에 비동기 방식을 사용해야 한다.

    비동기 I/O는 서버 프로그래밍의 필수

    서버 프로그램에서 성능 향상을 위해서 사용할 수 있는 다른 하나의 테크닉은 비동기(Asynchronous) I/O를 사용하는 것이다. 이를 이용하면 동시에 여러 개의 I/O 작업을 수행할 수 있는데 이는 어디까지나 작업의 시작만 비동기로 가능하다는 것이지 작업이 끝나는 부분은 즉, I/O 결과를 받는 부분은 동기화가 되어야 한다는 것이다. 만일 비동기 I/O의 결과를 그냥 무시해도 좋은 프로그램이라면 또다른 이야기가 되겠지만 아마 대부분의 프로그램에서는 비동기 I/O를 수행하고 그 결과를 살펴봐야 할 것이다.

    비동기 I/O에는 여러가지 방식이 존재한다. 간략히 참고 1에 윈도우에서 지원되는 비동기 I/O 방식을 나열해 보았다. 당연한 이야기이지만 이러한 비동기 I/O 방식은 특히 시간이 오래 걸리는 작업을 할 때 적합한 방식이다. 이러한 비동기 I/O 방식은 IOCP와 결합되었을 때 최적의 성능과 확장성을 자랑한다. 다시 정리해서 말하자면 비동기 I/O의 성능은 I/O가 끝났을 때 그 결과를 어떻게 확인하느냐에 달려 있는데 IOCP는 이러한 비동기 I/O를 가장 효율적으로 사용할 수 있게 해준다.


    참고 1. 윈도우의 비동기 I/O

    윈도우에서는 다양한 방식의 비동기 I/O를 제공한다 (사실 너무 다양한 방법을 제공한다.) 여기서는 간략히 언급하기로 하겠다. 다음에 기회가 닿으면 파일 I/O 관련 연재 기사를 다뤄볼 생각인데 그 때 자세히 언급하기로 하겠다.

    1> 오버랩드 I/O를 사용하기.

    예로 파일 I/O를 들어보자. 파일을 오픈할 때 CreateFile API를 사용하는데 이 때FILE_FLAG_OVERLAPPED를 인자로 주면 오버랩드 I/O를 수행할 수 있다. ReadFile과 WriteFile을 사용하여 I/O를 수행하게 되는데 이 함수들은 실행이 끝날 때까지 기다리지 않고 바로 리턴한다(비동기 I/O니까 당연한 이야기이지만). 이 때 마지막 인자로 OVERLAPPED 구조체를 사용하는데 여기에 이벤트(지난 회에 설명한 바 있다)를 지정하도록 되어있다. 작업이 끝나면 이 이벤트로 시그널이 가게 된다. 이벤트를 사용하는 대신에 함수의 실행이 끝났는지를 검사하기 위해 GetOverlappedResult 함수를 호출할 수도 있다. 참고로 ReadFile이나 WriteFile과 같은 함수는 꼭 파일 I/O에 사용되는 것이 아니란 점도 알아두기 바란다. 소켓에서 데이터를 읽고 쓰는데도 사용할 수 있다.

    2> 콜백 함수 사용하기

    기본적으로는 1<의 방식과 갖다. 다만 이벤트를 사용하는 대신에 콜백 함수를 지정해서 작업이 끝나면 그 함수를 호출하도록 하는 것이다. 이때는 ReadFile, WriteFile과 같은 함수 대신에 ReadFileEx와 WriteFileEx와 같은 함수를 사용해야 한다. 이 함수들은 인자 중의 하나로 콜백 함수의 주소를 받아들이도록 되어있다.

    3> IOCP 사용하기

    사실 IOCP를 비동기 I/O 작업 방식이라고도 할 수 있는데 이에 대해서는 이 기사의 뒷부분에서 자세히 살펴볼 것이다.


    지금까지 살펴본 것과 같은 기존의 멀티스레드 서버 프로그래밍의 문제점을 해결하기 위해 만들어진 것이 바로 IOCP이다. 기본적으로 IOCP는 비동기 I/O 작업을 지원하면서 적은 수의 스레드로 최대한의 요청을 처리하기 위한 방법이란 점이라고 이해하면 된다. 너무 많은 스레드가 동시에 동작함으로 인한 문제를 해결하면서 비동기 I/O 작업시 결과를 체크해야 하는 문제를 해결함으로써 서버 프로그램의 성능을 극대화하는 것이다.

    2. IOCP란 ?

    IOCP란 특정 입출력 객체(예를 들면 파일, 소켓, 메일 슬롯 등등)와 관련된 일종의 I/O 작업 결과 큐라고 생각할 수 있다. 좀더 자세히 설명하자면 먼저 IOCP 객체가 별도로 생성되어야 한다. 그 다음에 이 객체와 입출력 객체 중의 하나가 연결되어야 한다. 다음으로 이 입출력 객체에 비동기 I/O 작업이 수행되면 운영체제가 이 큐에 그 비동기I/O의 결과를 집어넣게 된다.

    또한 이 큐는 하나 이상의 스레드와 연관지어지게 된다 (스레드의 수는 비동기 I/O의 특성에 따라 달라지게 된다. 만일 I/O가 오래 걸리는 것이라면 스레드의 수는 적어도 관계없다. 하지만 I/O가 시간이 아주 조금밖에 안 걸리는 것이라면 스레드의 수는 많아야 한다). 운영체제는 큐에 결과가 있고 관련 스레드들 중에서 놀고 있는 놈이 있으면 그 스레드가 결과를 받아서 다음 작업을 수행할 수 있게 해준다. 즉, IOCP와 관련되어 동작할 수 있는 스레드를 미리 여러 개 만들어 놓고 이 중에서 필요에 따라 놀고 있는 것을 가져다 큐에서 비동기 I/O 결과를 읽어가도록 하는 것이다. 참고로 한 IOCP 객체는 동시에 여러 입출력 객체와 연관지어질 수 있다.

    자 이러한 과정을 코드를 통해 좀더 자세히 살펴보자. 그림 1을 참고하기 바란다. 본 기사의 서버 예제 프로그램의 코드를 바탕으로 설명하겠다.

    < 그림 1. IOCP의 동작 >

    1> IOCP의 생성

    먼저 첫번째 절차는 IOCP를 생성하는 것이다. 이는 CreateIoCompletionPort 함수를 통해 가능하다. 이 같은 함수를 이용해 입출력 객체와 IOCP를 연관짓는데 사용할 수 있다. 다음은 IOCP를 일단 생성하는 예(CreateIoCompletionPort 함수의 첫번째 인자로 INVALID_HANDLE_VALUE를 지정해야 한다. 이 함수에 대한 보다 상세한 설명은 참고 2를 보기 바란다)이다. 생성의 결과는 HANDLE로 리턴된다.

      g_hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
      if (NULL == g_hIOCP) 
      {
        printf("CreateIoCompletionPort failed: %d\n", GetLastError());
        CleanUp();
      }
    

    2> IOCP 큐에서 결과를 읽어들일 스레드 생성

    앞서 이야기한 것처럼 IOCP와 연관된 입출력 객체에 비동기 I/O를 수행하면 그 결과가 IOCP 큐에 쌓인다고 하였다. 이 큐에서 결과를 읽어들이는 일을 수행하는 스레드를 만들어야 한다. 다른 스레드 생성과 특별히 다를 것은 없다. 단 생성할 스레드의 수는 CPU수 X 2로 되어있다. 이는 마이크로소프트에서 권장하는 방식이다. 응용프로그램에 따라 이것이 적당할 수도 있고 훨씬 더 많은 스레드가 필요할 수도 있다. 이를 위해서 GetSystemInfo라는 함수를 이용해서 현재 시스템의 CPU수를 알아내는 코드가 들어있다.

    #define MAX_WORKER_THREAD	16
    
    DWORD g_dwThreadCount;
    unsigned int g_hThreads[MAX_NUMBER_OF_THREADS];
    
    …
    SYSTEM_INFO         systemInfo;
     DWORD dwThreadId;
    
    GetSystemInfo(&systemInfo);
    g_dwThreadCount = systemInfo.dwNumberOfProcessors * 2;
      …
    for (DWORD dwThread = 0;dwThread < g_dwThreadCount; dwThread++)
    {
      g_hThreads[dwThread] = _beginthreadex(NULL, 0, EchoThread, 
                                 g_hIOCP, 0, &dwThreadId);
      If (g_hThreads[dwThread] == NULL)
      {
        printf(“%d번째 스레드 생성에 실패했습니다.\n”, dwThread);
      }
    }
    

    위에서 볼 수 있는 것처럼 스레드의 생성에는 _beginthreadex 함수를 사용하였다. 스레드 함수는 EchoThread이며 스레드 함수의 인자로는 IOCP 핸들을 넘긴다. EchoThread 함수의 자세한 내용은 5>에서 살펴볼 것이다.

    3> IOCP와 입출력 객체의 연결

    다음은 이 IOCP와 입출력 객체를 연결하는 부분이다. 입출력 객체는 반드시 비동기 I/O 모드로 오픈되어야 한다. 연결된 객체에 대한 비동기 오버랩드 I/O 결과가 이 IOCP 큐에 들어간다. 예를 들어 소켓과 IOCP를 연결하는 간단한 예를 보면 다음과 같다.

    SOCKET sh;
    
    sh = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 
                 0, WSA_FLAG_OVERLAPPED);…
    if (sh != INVALID_SOCKET)
    {
    	CreateIoCompletionPort((HANDLE)sh, g_hIOCP, (ULONG_PTR)0, 0);
    

    먼저 소켓을 생성할 때 socket 함수를 사용한 것이 아니라 WSASocket 함수를 사용하였고 마지막 인자로 WSA_FLAG_OVERLAPPED가 지정되었다. 그 다음에 앞에서와 같은 CreateIoCompletionPort 함수를 사용하고 그 첫번째 인자로 소켓의 값을 지정하면 된다. 즉, CreateIoCompletionPort 함수는 IOCP의 생성에도 사용되고 생성된 IOCP와 입출력 객체를 연결하는데도 사용된다. 참고 2에서 CreateIoCompletionPort 함수의 세 번째 인자 설명을 보면 알 수 있겠지만 세 번째 인자가 가장 중요한 역할을 한다.

    앞서 잠깐 언급했던 것처럼 IOCP는 여러 개의 입출력객체와 동시에 연관지어질 수 있다. 예를 들어 여러 개의 소켓이 하나의 IOCP와 연관될 수 있다. 즉 그러한 소켓들에 대해 이루어지는 비동기 작업의 결과는 모두 그 하나의 IOCP 큐로 들어간다는 것이다. 그러기 때문에 IOCP 큐에서 비동기 작업 결과를 읽어들일 때 이 결과가 도대체 어느 입출력 객체로부터 온 것인지를 구분할 수 있는 방법이 있어야 한다. 이 때 CreateIoCompletionPort 함수의 세 번째 인자로 지정했던 값이 구분하는 역할을 담당한다. 뒤에서 살펴보겠지만 IOCP 큐에서 결과를 읽어들일 때 사용하는 함수는GetQueuedCompletionStatus라는 것이다. 이 함수의 세 번째 인자로 앞서 CreateIoCompletionPort 함수에서 지정했던 값이 넘어오게 되어 있다. 예제 프로그램에서는 입출력 객체마다 다음과 같은 구조체를 생성하고 이를 IOCP 객체와 연관지을 때 세번째 인자로 지정할 것이다.

    // IOCP와 연관되는 소켓마다 할당되는 구조체
    typedef struct _PER_SOCKET_CONTEXT 
    {
        SOCKET                 Socket;
        PPER_IO_CONTEXT       pIOContext;  
    } PER_SOCKET_CONTEXT, *PPER_SOCKET_CONTEXT;
    

    위에서 Socket은 클라이언트가 하나 연결될 때마다 부여되는 소켓이다. pIOContext는 이 소켓과의 입출력 작업에 사용되는 메모리 버퍼와 각종 구조체를 모아둔 구조체로 이 소켓내에서 벌어지는 입출력 작업의 상태를 나타낸다고 생각하면 된다. 다음과 같이 정의되어 있다.

    #define MAX_BUFF_SIZE       8192
    // 소켓에 대한 입출력 작업에 사용되는 구조체
    typedef struct _PER_IO_CONTEXT 
    {
        WSAOVERLAPPED        Overlapped;
        char                     Buffer[MAX_BUFF_SIZE];
        WSABUF                 wsabuf;
        int                       nTotalBytes;
        int                       nSentBytes;
        IO_OPERATION           IOOperation;
    } PER_IO_CONTEXT, *PPER_IO_CONTEXT;
    

    먼저 첫번째 필드인 Overlapped는 사실 ReadFile, WriteFile과 같은 함수를 이용해서 수행하는 비동기 I/O에서 사용하는 OVERLAPPED 구조체와 동일한 것이다. typedef로 이름만 바꾸었을 뿐이다. 뒤에서 WSARecv와 WSASend를 이용해서 비동기 I/O를 해볼 텐데 그 때 이 필드가 사용된다. 그 함수들을 호출할 때 로컬 변수로 사용하면 안 될까 생각할 수도 있는데 이 변수는 작업이 끝날 때까지 접근이 가능해야 하기 때문에 이렇게 글로발하게 별도로 잡아두는 것이다. (로컬 변수로 잡고 그걸 인자로 비동기 함수를 호출하면 그 변수가 선언한 블럭을 벗어날 경우 그 로컬 변수는 더 이상 유효하지 않다. 이런 문제를 해결하기 위함이다)

    사실 이 구조체는 의도적으로 WSAOVERLAPPED 타입의 필드로부터 시작한다. 비동기 I/O 작업에 사용되는 WSASend, WSARecv함수의 경우 인자 중에 WSAOVERLAPPED 타입의 변수를 받아들이는 인자가 있다. 또한 비동기 I/O가 끝나고 그 결과를 IOCP 큐에서 읽어들일 때 앞서 사용했던WSAOVERLAPPED 타입의 변수를 그대로 받아볼 수 있다.

    사실 Overlapped가 이 구조체의 첫 번째 필드이기 때문에 이 필드의 주소나 이 구조체의 주소나 동일하다. WSASend와 WSARecv를 이용해 비동기 I/O를 개시할때 이 구조체의 Overlapped 필드의 주소를 넘기면 사실 이것이PER_IO_CONTEXT 타입 변수의 주소를 넘긴 것이나 다름없다. 그렇게 해서 비동기 I/O의 결과를 큐에서 꺼낼 때 현재 작업의 상태를 알 수 있는 것이다. 앞서 이야기한 것처럼 PER_IO_CONTEXT 구조체는 현재 비동기 I/O 작업의 상태를 나타낸다.

    두 번째 필드인 Buffer는 읽기/쓰기 작업을 할때 사용할 메모리 영역이다. 세 번째 필드인 wsabuf는 읽기/쓰기 작업시 데이터의 시작 포인터와 데이터 크기를 지정하는데 사용되는 구조체이다. WSASend와 WSARecv 함수의 인자로 필요하다. 네 번째 인자인 nTotalBytes는 쓰기 작업시 전송해야할 데이터의 양을 나타낸다. 다섯 번째 인자인 nSendBytes는 지금까지 전송된 데이터의 양을 나타낸다. 마지막 인자인 IOOperation은 다음과 같이 정의된 열거자로서 현재 소켓에 대해 진행 중인 작업의 종류를 나타낸다.

    typedef enum _IO_OPERATION 
    {
        ClientIoRead, // 읽기 작업 진행 중
        ClientIoWrite  // 쓰기 작업 진행 중
    } IO_OPERATION, *PIO_OPERATION;
    

    이제 이를 바탕으로 예제 프로그램의 코드를 살펴보자. 다음에서 볼 수 있는 것처럼 클라이언트로부터의 요청이 들어오기를 대기하다가 요청이 들어오면 그로 인해 생성되는 소켓을 인자로 위의 작업을 수행하는UpdateCompletionPort라는 함수를 별도로 만들었다.

      SOCKET                 sdAccept = INVALID_SOCKET;
      PPER_SOCKET_CONTEXT lpPerSocketContext = NULL;
    
      while (g_bEndServer == FALSE) 
      {
        // 클라이언트가 들어오기를 대기한다.
        sdAccept = WSAAccept(g_sdListen, NULL, NULL, NULL, 0);
        if (SOCKET_ERROR == sdAccept) 
        {
          printf("WSAAccept: %d\n", WSAGetLastError());
          CleanUp();
        }
        printf("클라이언트가 하나 들어왔습니다\n.");
        // 만들어진 sdAccept 소켓에 앞서본 PER_SOCKET_CONTEXT 구조체를 할당한다.
        // 그리고나서 이를 IOCP 객체와 연결한다. 두 번째 인자로는 이제 일어날 작업의     
        // 종류를 명시한다. 에코우 서버이므로 첫 번째 할 작업은 클라이언트로부터 
        // 데이터를 읽는 것이기 때문에 ClientIoRead를 명시한다.
        lpPerSocketContext = UpdateCompletionPort(sdAccept, ClientIoRead, TRUE);
        if (NULL == lpPerSocketContext) 
        {
          CleanUp();
        }
        // …
    

    UpdateCompletionPort 함수의 내용은 다음과 같다. 첫 번째 인자로 지정된 소켓을 바탕으로 앞서본 PER_SOCKET_CONTEXT 구조체를 할당한다. 이것과 소켓을IOCP 객체와 연결한다. 두 번째 인자로는 이제 이 소켓에 일어날 작업의 종류를 명시한다. 에코우 서버이므로 첫 번째 할 작업은 클라이언트로부터 데이터를 읽는 것이기 때문에 ClientIoRead를 명시한다.

    // 첫번째 인자로 명시된 소켓을 IOCP에 연결짓는다.
    PPER_SOCKET_CONTEXT UpdateCompletionPort(SOCKET sd, IO_OPERATION ClientIo)
    {
      PPER_SOCKET_CONTEXT lpPerSocketContext;
    
      // PER_SOCKET_CONTEXT를 할당하는데 CtxtAllocate 함수를 사용한다.
      lpPerSocketContext = CtxtAllocate(sd, ClientIo);
      if (lpPerSocketContext == NULL) 
        return NULL;
    
      // 할당된 구조체와 소켓을 g_hIOCP에 연결한다.
      g_hIOCP = CreateIoCompletionPort((HANDLE)sd, g_hIOCP, 
             (DWORD)lpPerSocketContext, 0);
      if (NULL == g_hIOCP) 
      {
        printf("CreateIoCompletionPort: %d\n", GetLastError());
        if (lpPerSocketContext->pIOContext)
          free(lpPerSocketContext->pIOContext);
        free(lpPerSocketContext);
        return(NULL);
      }
    
      // 이 구조체를 링크드 리스트에 보관한다. 
      CtxtListAddTo(lpPerSocketContext);
      return(lpPerSocketContext);
    }
    

    위의 코드를 보면 PER_SOCKET_CONTEXT 타입의 구조체를 할당하기 위해서 CtxtAllocate라는 함수를 사용하고 있다. 이 함수에 대해서는 뒤에서 다시 설명할 텐데 구조체를 할당하고 초기화하는 일을 담당한다. 그 다음에 CreateIoCompletionPort 함수를 이용해서 이 구조체와 소켓을 IOCP에 연결한다. 마지막으로 이렇게 생성된 구조체를 전체적으로 관리하기 위해서 CtxtListAddTo 함수를 호출한다. 이 함수 역시 뒤에서 다시 설명하겠다.


    참고 2. CreateIoCompletionPort

    이 함수의 원형은 다음과 같다.

    HANDLE CreateIoCompletionPort(HANDLE FileHandle, 
       HANDLE ExistingCompletionPort, 
       ULONG_PTR CompletionKey, 
       DWORD NumberOfConcurrentThreads);
    

    첫 번째 인자인 FileHandle은 IOCP의 대상이 되는 입출력 객체의 핸들이어야 한다. 이 객체는 반드시 오버랩드 I/O 모드로 오픈된 것이어야 한다. 만일 이 인자의 값이 INVALID_FILE_HANDLE로 주어지고 두 번째 인자의 값이 NULL이 되면 이 함수의 리턴값은 새롭게 생성된 IOCP의 핸들이 된다. 이 때 세번째 인자의 값은 무시된다.

    두 번째 인자인 ExistingCompletionPort는 IOCP에 대한 핸들을 지정하기 위해 사용된다. 이 경우 첫번째 인자의 값은 입출력 객체의 핸들이 되어야 하며 이 둘은 연결되게 된다. 그런 경우 이 함수는 두번째 인자로 지정된 IOCP 핸들을 그대로 다시 리턴한다.

    세 번째 인자인 CompletionKey는 IOCP와 연결된 입출력 객체에 특정한 포인터라고 할 수 있다. 한 IOCP에는 여러 개의 입출력 객체가 동시에 연관될 수 있기 때문에 이 값을 통해 어느 객체로부터의 I/O 결과인지를 구분할 수 있다. 따라서 여러 개의 입출력 객체를 사용할 경우 이 인자는 아주 중요한 역할을 하게 된다.

    마지막 인자인NumberOfConcurrentThreads는 이 IOCP에 연관지어지는 스레드의 최대 수를 지정하는데 사용된다. 0을 주면 시스템의 자원이 허용하는 한 스레드가 계속 만들어지게 된다.


    4> 비동기 I/O의 수행

    앞 절차에서 소켓이 제대로 IOCP에 연결이 되고 나면 이제 그 소켓에 대해 비동기 I/O 작업을 수행해야 한다. 소켓의 경우, WSASend와 WSARead를 호출하면 그 결과는 g_hIOCP라는 것이 가리키는 큐안에 쌓이게 된다. 다음과 같은 함수들이 비동기 I/O 결과를 IOCP큐에 넣는다.

  • ReadFile, WriteFile
  • WSASend, WSARecv
  • ConnectNamedPipe
  • DeviceIoControl
  • LockFileEx
  • ReadDirectoryChanges
  • TransactNamedPipe
  • WaitCommEvent

    예제 프로그램에서는 UpdateCompletionPort 함수의 호출이 성공적으로 끝난 후에 클라이언트에서 보내는 데이터를 받기 위해서 WSARead 함수를 한번 호출한다. 참고로 다시 한번 이야기하자면 이 서버 프로그램은 에코우 서버이기 때문에 클라이언트가 보낸 데이터를 그대로 다시 클라이언트로 전송한다.

        lpPerSocketContext = UpdateCompletionPort(sdAccept, ClientIoRead);
        if (NULL == lpPerSocketContext) 
        {
          CleanUp();
          return 1;
        }
    
        // 소켓에 비동기 읽기를 수행한다. 
        nRet = WSARecv(sdAccept, &(lpPerSocketContext->pIOContext->wsabuf), 1, 
                    &dwRecvNumBytes, &dwFlags,
                    &(lpPerSocketContext->pIOContext->Overlapped), NULL);
        if (nRet == SOCKET_ERROR && (ERROR_IO_PENDING != WSAGetLastError())) 
        {
          printf("WSARecv Failed: %d\n", WSAGetLastError());
          CloseClient(lpPerSocketContext);
        }
      } //while
    

    위의 WSARecv 함수 호출에서 6번째 인자를 눈여겨 보기 바란다. WSAOVERLAPPED 구조체의 변수를 지정하는데 PER_IO_CONTEXT의 Overlapped 필드를 넘기고 있다. 3>에서 설명한 것처럼 이는 사실 pIOContext의 주소를 넘기는 것과 동일한 효과를 갖는다.

    아무튼 WSARecv로 인한 읽기 작업이 완료되면 이는 IOCP 큐에 들어간다. 이를 읽어들이는 작업은 앞에서 만든 스레드들에서 수행한다. 이 함수는 비동기 함수이기 때문에 바로 리턴하고 그리고나서 코드는 다시 while 루프로 선두로 가서 다른 클라이언트로부터의 연결을 대기한다.

      while (g_bEndServer == FALSE) 
      {
        // 클라이언트가 들어오기를 대기한다.
        sdAccept = WSAAccept(g_sdListen, NULL, NULL, NULL, 0);
        …
    

    즉, main 함수는 초기화 작업을 하고 난 뒤부터는 클라이언트로부터의 소켓연결이 맺어지기를 기다렸다가 만들어지면 이를 IOCP와 연결한 뒤에 WSARecv를 한번 호출하는 일만 한다. 실제 작업은 모두 스레드에서 이루어진다.

    참고로 WSASend와 WSARecv의 함수 원형을 살펴보자.

    int WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, 
           LPDWORD  lpNumberOfBytesRecvd, LPDWORD lpFlags, 
           LPWSAOVERLAPPED lpOverlapped, 
           LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
    
    int WSASend(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, 
           LPDWORD lpNumberOfBytesSent, DWORD dwFlags, 
           LPWSAOVERLAPPED lpOverlapped, 
           LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
    

    이 두 함수는 비슷한 인자를 많이 갖고 있다. 먼저 모두 첫번째 인자는 소켓 핸들이다. 두 번째 인자는 WSABUF라는 구조체에 대한 포인터로 보낼 데이터에 대한 정보이거나 데이터를 받을 버퍼에 대한 정보이다. WSABUF는 다음과 같이 버퍼의 시작 주소와 버퍼의 크기를 지정하는 두개의 필드로 구성되어 있다.

    Typedef struct __WSABUF
    {
    u_long len; // 버퍼 크기
      char FAR *buf; // 버퍼 시작 주소
    } WSABUF, FAR *LPWASBUF;
    

    이 두 번째 인자로는 WSABUF 배열의 주소를 지정할 수도 있다. 그 경우 차례로 여러 버퍼의 데이터를 전송하거나 (WSASend의 경우) 받은 데이터를 여러 버퍼로 옮기는 역할(WSARecv의 경우)을 한다. 세 번째 인자는 이 두 번째 인자가 가리키는 WSABUF 변수의 수를 나타낸다. 배열을 지정했을 경우에는 그 크기를 이 인자로 지정해주면 된다. 배열이 아니라면 그냥 1을 지정하면 된다. 여기서 한가지 알아야 할 점은 이 두 함수 모두 지정한 크기만큼 입출력이 종료된 다음에 리턴되는 것이 아니란 점이다. WSARecv 같은 경우에는 읽어올 데이터가 생기면 지정된 크기와 관계없이 바로 작업을 종료한다. WSASend의 경우에는 소켓 버퍼가 꽉 차서 데이터를 지정된 크기만큼 보낼 수 없으면 일단 보낼 수 있는 만큼 보내고 만다.

    네 번째 인자는 각기 실제로 전송된 데이터(WSASend의 경우)와 실제로 읽어들인 데이터(WSARecv의 경우)의 크기가 들어간다. 그런데 이 함수들을 예제 프로그램에서처럼 비동기 모드로 사용할 경우에는 이 인자로 리턴되는 값은 함수 자체의 리턴값이 0인 경우에만 의미가 있다. 0인 경우는 바로 작업이 끝난 경우이다. 함수가 바로 끝나지 않을 경우에는 SOCKET_ERROR가 리턴되고 이 때 GetLastError 함수를 호출해보면 그 값이 WSA_IO_PENDING일 것이다.

    다섯 번째 인자는 약간 복잡한데 일단 대부분 0이 리턴되거나 (WSARecv의 경우) 0이 지정(WSASend의 경우)된다고 알아두기 바란다. 여섯 번째 인자는 WSAOVERLAPPED 구조체에 대한 포인터를 지정하는 부분이다. IOCP를 사용하는 경우에는 hEvent 필드의 값은 반드시 NULL이 지정되어야 한다. 마지막 인자는 콜백함수를 지정하는데 사용된다. 이 콜백함수의 원형은 다음과 같다.

    void CALLBACK CompletionROUTINE(DWORD dwError, DWORD cbTransferred,
        LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags);
    

    만일 여섯 번째 인자와 마지막 인자가 모두 NULL이면 이 함수들은 동기 모드로 동작한다. 여섯 번째 인자와 마지막 인자가 모두 지정되면 작업이 종료되었을 때 마지막 인자로 지정된 함수가 호출된다. 여섯 번째 인자만 지정되고 첫 번째 인자로 지정된 소켓이 IOCP와 연결되어 있으면 이 함수의 결과는 IOCP 큐에 들어간다. 사실 이 두 함수의 인자들을 제대로 이해할 수 있다면 윈도우 운영체제의 입출력 함수는 다 이해했다고 봐도 무방하다.

    5> 비동기 I/O 결과 읽기

    앞서 수행된 비동기 I/O의 결과를 읽어들이려면 GetQueuedCompletionPort라는 함수를 이용해야 한다. 이 함수 원형에 대한 설명은 참고 3에 있다. 이 함수는 IOCP 큐안에 읽어들일 비동기 I/O 결과가 있으면 이를 읽어가지고 리턴한다. 읽어올 것이 없으면 읽어올 것이 생길 때까지 리턴하지 않는다. 다음 코드처럼 이 함수는 무한루프안에서 계속적으로 호출되는 것이 일반적이다.

    While (1)
    {
      GetQueuedCompletionStatus(…);
      // 읽어들인 결과를 바탕으로 다음 일을 수행한다.
      …
    }
    

    예제 프로그램과 같은 에코우 서버에서는 특정 소켓에 대해 읽기 작업이 완료된 결과를 읽어들였으면 이를 비동기로 쓰는 작업을 하고, 쓰기 작업이 완료된 결과를 읽어들였으면 다시 비동기로 읽기 작업을 수행한다. 앞서 이야기한 것처럼 GetQueuedCompletionPort 함수의 세 번째 인자로는 현재 이 소켓에 대해 따로 할당된PER_SOCKET_CONTEXT 구조체의 포인터가 리턴되고 이 것의 pIOContext 필드를 보면 현재 진행중인 작업의 상태를 알 수 있다. pIOContext의IOOperation 필드의 값이ClientIoRead이면 지금 큐에서 읽어온 작업이 읽기 작업의 결과인 것이고 ClientIoWrite이면 쓰기 작업인 것이다.

    위의 코드를 좀더 예제 프로그램에 맞게 고쳐보면 다음과 같은 식이다.

    While (1)
    {
      GetQueuedCompletionStatus(…);
      // 읽어들인 결과를 바탕으로 다음 일을 수행한다.
      만일 읽어들인 결과가 읽기 작업이면
        읽어들인 데이터를 그대로 다시 서버로 보낸다 (물론 비동기 I/O)
      만일 읽어들인 결과가 쓰기 작업이면
        만일 앞서 쓰기 요청한 것이 다 전송되지 않았으면
          전송안 된 부분만 다시 전송한다
        다 전송되었으면
          읽기 비동기 작업을 소켓에 수행한다.
    }
    

    참고 3. GetQueuedCompletionStatus

    이 함수의 원형은 다음과 같다.

    BOOL GetQueuedCompletionStatus(
        HANDLE CompletionPort,       
        LPDWORD lpNumberOfBytes, 
        PULONG_PTR lpCompletionKey,
        LPOVERLAPPED *lpOverlapped,
        DWORD dwMilliseconds);
    

    첫 번째 인자인 CompletionPort로는 앞서 생성된 IOCP 객체의 핸들을 지정한다.

    두 번째 인자로는 지금 읽어온 I/O 작업의 결과로 읽거나 쓴 데이터의 크기가 바이트 단위로 지정된다. 즉 이 인자의 값은 운영체제에서 지정한다.

    세 번째 인자인 lpCompletionKey역시 운영체제에 의해 채워져 리턴되는 값이다. CreateIoCompletionPort 함수로 IOCP 객체를 생성할 때 세 번째 인자로 지정한 값이 여기로 리턴된다. 앞서 이야기한 것처럼 한 IOCP 객체로 둘 이상의 입출력 디바이스를 처리할 수 있기 때문에 이를 구분하는 값이 여기로 지정된다고 생각하면 된다.

    네 번째 인자인 lpOverlapped 역시 운영체제에 의해 값이 지정되는데 이는 한 입출력 디바이스내에서 각각의 입출력 작업을 구별하는 역할을 한다. 이 값은 사실 앞서 비동기 작업에서 사용된 OVERLAPPED 구조체의 주소가 그대로 들어온다. 그렇기 때문에 비동기 I/O 작업시에 OVERLAPPED 구조체를 스택에 있는 것을 사용하면 안 되고 각 작업마다 서로 다른 OVERLAPPED 구조체가 사용되어야 하는 것이다.

    마지막 인자인dwMilliseconds는 IOCP 큐에 결과가 없을 경우 얼마나 더 대기하다가 리턴할 것인지를 밀리세컨드 단위로 지정한다. 만일 타임아웃이 나서 리턴할 경우에는 GetQueuedCompletionStatus 함수의 리턴값은 FALSE가 되고 네 번째인자로는 NULL이 지정된다. 읽어올 것이 생길 때까지 대기하도록 하고 싶으면 이 인자로 INFINITE를 지정하면 된다.

    위의 플로우를 염두에 두고 이제 예제 프로그램의 스레드 코드를 실제로 살펴보자. 주석을 자세히 달아놓았으므로 주석과 함께 코드를 살펴보기 바란다.

    DWORD WINAPI EchoThread (LPVOID WorkThreadContext)
    {
      // 앞서 스레드 생성시 스레드 함수의 인자로 IOCP 핸들을 지정했었다.
      // 인자를 IOCP 핸들로 캐스팅한다.
      HANDLE hIOCP = (HANDLE)WorkThreadContext;
      BOOL   bSuccess = FALSE;
      int      nRet;
      LPOVERLAPPED    lpOverlapped = NULL;
      PPER_SOCKET_CONTEXT lpPerSocketContext = NULL;
      PPER_IO_CONTEXT     lpIOContext = NULL; 
      WSABUF buffRecv;
      WSABUF buffSend;
      DWORD  dwRecvNumBytes = 0;
      DWORD  dwSendNumBytes = 0;
      DWORD  dwFlags = 0;
      DWORD  dwIoSize;
        
      while (TRUE) 
      {
        // IOCP 큐에서 비동기 I/O 결과를 하나 읽어온다.
        bSuccess = GetQueuedCompletionStatus(hIOCP, &dwIoSize, 
                 (LPDWORD)&lpPerSocketContext, &lpOverlapped,INFINITE);
        if (!bSuccess) 
          printf("GetQueuedCompletionStatus: %d\n", GetLastError());
    
        // CleanUp 함수에 의해서 스레드의 강제 종료 명령이 내려지면.. 
        if (lpPerSocketContext == NULL)  return 0;
        if (g_bEndServer) return 0;
     
        // 클라이언트와의 소켓 연결이 끊어졌으면…
        if (!bSuccess || (bSuccess && (0 == dwIoSize))) 
        {
          // lpPerSocketContext를 메모리에서 제거한다.
          CloseClient(lpPerSocketContext); 
          continue;
        }
    
        /* 앞서 WSASend와 WSARecv에 의해 I/O 작업을 할 때 넘겼던 WSAOVERLAPPED    
    타입의 변수가 사실은 PER_IO_CONTEXT 타입의 시작이기도 하므로 이를 캐스팅하
    여 사용가능하다. */
        lpIOContext = (PPER_IO_CONTEXT)lpOverlapped;
        switch (lpIOContext->IOOperation) // 끝난 작업 종류가 무엇인가 ?
        {
            case ClientIoRead: // 읽기 작업인가 ?
            // --------------------------------------------
            // 받은 것을 그대로 보낸다. 즉, 다음 작업은 쓰기 작업이다.
            // --------------------------------------------
            printf("%s를 받았고 이를 재전송합니다.\n.", lpIOContext->wsabuf.buf);
              lpIOContext->IOOperation = ClientIoWrite; // 이제 쓰기 작업이 진행됨을 표시
              // 얼마큼 전송할 것인지 명시한다. 받은 만큼 보낸다. 이는 상태를 기록하기
              // 위함이지 WSASend 함수와는 관련없다.
              lpIOContext->nTotalBytes = dwIoSize; 
              // 전송된 데이터 크기. 아직 보낸 것이 없으므로 0
              lpIOContext->nSentBytes  = 0;
            // WSASend에게 보낼 데이터의 포인터와 크기를 지정한다.
            // 받은 데이터가 이미 lpIOContext->wsabuf.buf에 있다.
            lpIOContext->wsabuf.len  = dwIoSize; // 크기 지정
            dwFlags = 0;
            nRet = WSASend(lpPerSocketContext->Socket,
                  &lpIOContext->wsabuf, 1, &dwSendNumBytes,
                  dwFlags, &(lpIOContext->Overlapped), NULL);
            if (SOCKET_ERROR == nRet && (ERROR_IO_PENDING != WSAGetLastError())) 
            {
              printf("WSASend: %d\n", WSAGetLastError());
              CloseClient(lpPerSocketContext);
            }
            break;
    
          case ClientIoWrite: // 쓰기 작업인가 ?
            // ----------------------------------------------------
            // 전송이 다 되었는지 확인한다. 다 전송되지 않았으면 아직 전송되지 
            // 않은 데이터를 다시 보낸다. 다 전송되었으면 WSARecv를 호출해서
            // 다시 받기 모드로 진입한다.  
            // --------------------------------------------
            lpIOContext->nSentBytes  += dwIoSize; // 전송된 데이터 크기 업데이트
            dwFlags = 0;
            if (lpIOContext->nSentBytesnTotalBytes) // 다 전송되지 않았으면
            {
              // 마저 전송해야 하므로 아직 보내기모드
              lpIOContext->IOOperation = ClientIoWrite;
              // -----------------------
              // 전송되지 않은 부분을 보낸다. 
              // -----------------------
              // 버퍼 포인터를 업데이트하고
              buffSend.buf = lpIOContext->Buffer + lpIOContext->nSentBytes;
              // 보내야할 데이터의 크기를 남은 데이터의 크기만큼으로 줄인다.
              buffSend.len = lpIOContext->nTotalBytes - lpIOContext->nSentBytes;
              nRet = WSASend (lpPerSocketContext->Socket,
                         &buffSend, 1, &dwSendNumBytes,
                         dwFlags, &(lpIOContext->Overlapped), NULL);
              // SOCKET_ERROR가 리턴된 경우에는 반드시 WSAGetLastError의 리턴값이
              // ERROR_IO_PENDING이어야 한다.
              if (SOCKET_ERROR == nRet && (ERROR_IO_PENDING != WSAGetLastError())) 
              {
                printf ("WSASend: %d\n", WSAGetLastError());
                CloseClient(lpPerSocketContext);
              }
            }
            else // 데이터가 전부 전송된 경우
            {
              // 다시 이 소켓으로부터 데이터를 받기 위해 WSARecv를 호출한다.
              lpIOContext->IOOperation = ClientIoRead; 
              dwRecvNumBytes = 0;
              dwFlags = 0;
              buffRecv.buf = lpIOContext->Buffer; // 수신버퍼 지정
              // 읽어들일 데이터 크기 지정. 사실 이 크기만큼 데이터를 읽어들여야 
              // 그 결과가 IOCP큐에 들어가는 것은 아니다.  이 크기 이상 안 
              // 읽어들일 뿐이고 데이터가 이용가능한 만큼 IOCP큐에 넣는다.
              buffRecv.len = MAX_BUFF_SIZE;
              nRet = WSARecv(lpPerSocketContext->Socket,
                            &buffRecv, 1, &dwRecvNumBytes,
                            &dwFlags, &(lpIOContext->Overlapped), NULL);
              // SOCKET_ERROR가 리턴된 경우에는 반드시 WSAGetLastError의 리턴값이
              // ERROR_IO_PENDING이어야 한다.
              if (SOCKET_ERROR == nRet && (ERROR_IO_PENDING != WSAGetLastError())) 
              {
                printf ("WSARecv: %d\n", WSAGetLastError());
                CloseClient(lpPerSocketContext);
              }
            }
            break;
          } //switch
        } //while
        return(0);
    }
    

    자 이상으로 IOCP가 어떤 식으로 동작하는지 알아보았다. 단계별로 설명과 코드를 잘 살펴보면 어떻게 동작하는지 더 쉽게 이해할 수 있을 것이다.

    3. 예제 프로그램의 기타 코드 설명

    예제 프로그램에서 설명이 안 된 코드는 서버와 연결된 클라이언트의 리스트를 관리하는 함수들(CtxtAllocate, CtxtListFree, CtxtListAddTo, CtxtListDeleteFrom)과 청소 함수(CleanUp, CloseClient), 대기 소켓 생성함수(CreateListenSocket)등이다. 대기 소켓 생성 함수는 이미 지난 연재에서 살펴본 내용(사실 socket 대신에 WSASocket을 호출하는 부분만 다르다)이기 때문에 여기서는 다른 함수들에 대해서만 알아보겠다.

    클라이언트 리스트 관리 함수들

    접속하는 클라이언트가 생길 때마다 이는g_CtxtList에 기록된다. 이는CptrList 타입의 링크드 리스트 클래스이고 이 변수로의 접근은 모두g_CriticalSection이란 크리티컬 섹션에 의해 한번에 한 스레드로 제한된다.

    CtxtAllocate는 인자로 지정된 소켓에 PER_SOCKET_CONTEXT 구조체를 하나 할당하고 그 구조체를 초기화한 다음에 이를 리턴한다. 할당에 실패하면 NULL을 리턴한다. PER_SOCKET_CONTEXT 구조체의 IO_PER_CONTEXT 타입의 필드인 pIOContext의 필드를 초기화하는 부분을 눈여겨 봐두기 바란다.

    PPER_SOCKET_CONTEXT CtxtAllocate(SOCKET sd, IO_OPERATION ClientIO)
    {
      PPER_SOCKET_CONTEXT lpPerSocCon;
    
      lpPerSocCon = (PPER_SOCKET_CONTEXT)malloc(sizeof(PER_SOCKET_CONTEXT));
      if (lpPerSocCon)
      {
        lpPerSocCon->pIOContext = (PPER_IO_CONTEXT)
            malloc(sizeof(PER_IO_CONTEXT));
        if (lpPerSocCon->pIOContext) 
        {
          lpPerSocCon->Socket = sd;
          memset(&lpPerSocCon->pIOContext->Overlapped, 
             0, sizeof(OVERLAPPED));
          lpPerSocCon->pIOContext->IOOperation = ClientIO;
          lpPerSocCon->pIOContext->nTotalBytes = 0;
          lpPerSocCon->pIOContext->nSentBytes = 0;
          lpPerSocCon->pIOContext->wsabuf.buf = lpPerSocCon->pIOContext->Buffer;
          lpPerSocCon->pIOContext->wsabuf.len = MAX_BUFF_SIZE;
        }
        else 
        {
          free(lpPerSocCon);
          lpPerSocCon = NULL;
        }
      }
      return(lpPerSocCon);
    }
    

    나머지 세 함수들은 간단하다. CptrList 클래스를 사용해본 이라면 이 함수들의 소스를 이해하기가 아주 쉬울 것이다. 여기서는 CtxtListAddTo와 CtxtListDeleteFrom 함수만 살펴보겠다.

    // g_CtxtList에 lpPerSocketContext가 가리키는 항목을 추가한다
    VOID CtxtListAddTo (PPER_SOCKET_CONTEXT lpPerSocketContext)
    {
      EnterCriticalSection(&g_CriticalSection);
      g_CtxtList.AddTail(lpPerSocketContext); // 리스트의 끝에 붙인다.
      LeaveCriticalSection(&g_CriticalSection);
      return;
    }
    
    // g_CtxtList에서 lpPerSocketContext가 가리키는 항목을 제거한다.
    VOID CtxtListDeleteFrom(PPER_SOCKET_CONTEXT lpPerSocketContext)
    {
      EnterCriticalSection(&g_CriticalSection);
      if (lpPerSocketContext)
      {
        POSITION pos = g_CtxtList.Find(lpPerSocketContext);
        if (pos)
        {
          g_CtxtList.RemoveAt(pos);
          if (lpPerSocketContext->pIOContext)
            free(lpPerSocketContext->pIOContext);
          free(lpPerSocketContext);
        }
      }
      LeaveCriticalSection(&g_CriticalSection);
      return;
    }
    

    청소 함수들

    여기서는 CleanUp 함수의 코드를 보기로 하겠다. 이 함수를 프로그램이 종료될 때 호출되는 함수로 모든 스레드가 종료되기를 기다렸다가 클라이언트 리스트에 할당되었던 자료구조들을 제거하고 최종적으로 IOCP와 대기 소켓을 제거하는 일을 수행한다.

    void CleanUp()
    {
        if (g_hIOCP)        
        {
            // 스레드를 강제 종료하도록 한다. 
            // 참고 4와 EchoThread의 if (lpPerSocketContext == NULL)를 같이 보기 바란다.  
            for (DWORD i = 0; i < g_dwThreadCount; i++)
                PostQueuedCompletionStatus(g_hIOCP, 0, 0, NULL);
        }
    
        // 모든 스레드가 실행을 중지했는지 확인한다.
        if (WAIT_OBJECT_0 != WaitForMultipleObjects( g_dwThreadCount,  g_hThreads,
                         TRUE, 1000))
            printf("WaitForMultipleObjects failed: %d\n", GetLastError());
        else
            for (DWORD i = 0; i < g_dwThreadCount; i++) // 스레드 핸들을 모두 닫는다.
            {
                if (g_hThreads[i] != INVALID_HANDLE_VALUE) CloseHandle(g_hThreads[i]);
                    g_hThreads[i] = INVALID_HANDLE_VALUE;
            }
        // g_CtxtList에 들어있는 클라이언트들을 모두 제거한다.
        CtxtListFree();
        // IOCP를 제거한다.  
        if (g_hIOCP)    
        {
            CloseHandle(g_hIOCP);
            g_hIOCP = NULL;
        }
        // 대기 소켓을 제거한다.
        if (g_sdListen != INVALID_SOCKET) 
        {
            closesocket(g_sdListen); 
            g_sdListen = INVALID_SOCKET;
        }
    
        DeleteCriticalSection(&g_CriticalSection); // 크리티컬 섹션을 제거한다.
        WSACleanup(); // 윈속 라이브러리를 해제한다.
    }
    


    참고 4. PostQueuedCompletionPort

    앞에서 설명한 것처럼 이 함수는 IOCP 큐에 마치 비동기 작업이 끝나서 그 결과가 큐에 들어가는 것처럼 흉내내는 기능을 한다. 그렇기 때문에 이 함수의 인자들을 보면 GetQueuedCompletionStatus 함수에 있는 것과 동일하다. 이 함수의 원형은 다음과 같다.

    BOOL PostQueuedCompletionStatus(
    HANDLE CompletionPort,
    DWORD dwNumberOfBytesTransferred,
      ULONG_PTR dwCompletionKey, 
    LPOVERLAPPED lpOverlapped);
    

    첫 번째 인자인 CompletionPort로는 지금 만들어내는 I/O 작업의 결과가 들어갈 IOCP 객체의 핸들을 지정한다.

    두 번째 인자인 dwNumberOfBytesTransferred는 GetQueuedCompletionStatus 함수의 두 번째 인자로 넘어갈 값을 지정한다.

    세 번째 인자인 dwCompletionKey는 두 번째 인자와 마찬가지로 GetQueuedCompletionStatus 함수의lpCompletionKey 인자로 들어갈 값을 지정하는데 사용된다.

    네 번째 인자인 lpOverlapped는 앞서 인자들과 마찬가지로 GetQueuedCompletionStatus 함수의 네 번째 인자로 들어갈 OVERLAPPED 구조체의 값을 넘긴다.

    이 함수가 성공적으로 인자로 지정된 값들을 IOCP 큐에 넣으면 0이 아닌 값이 리턴된다. 실패시에는 0이 리턴되며 이 때는 GetLastError 함수를 호출해서 에러의 원인을 찾아볼 수 있다.

    예제 프로그램의 실행 화면은 그림 2와 같다.

    < 그림 2. 예제 프로그램의 실행화면 >

    이 것으로 IOCP에 대한 장황한 설명을 마치겠다. 아마 이해하기가 그리 쉽지 않을 것이다. 필자의 경우에도 이를 이해하는데 상당한 시간을 소모했으며 위의 예제 프로그램을 바탕으로 실제 환경하에서 동작하는 프로그램을 만드는데도 상당한 시간을 보냈다. 이해하기는 어렵지만 IOCP는 스레드을 최대한으로 활용할 수 있도록 해주는 메커니즘이다. 특히 소켓으로 다중 사용자의 요구를 처리해야 하는 프로그램을 만들어야 한다면 IOCP는 최적의 솔루션이 아닌가 싶다.

    참고문헌
    1. INFO: Design Issues When Using IOCP in a Winsock Server (Q192800) - http://support.microsoft.com/default.aspx?scid=kb;EN-US;q192800
    2. Programming Server-Side Applications for Microsoft Windows 2000, Chapter 2 Devico I/O and Interthreaded Communication
    3. Writing Windows NT Server Applications in MFC Using I/O Completion Ports - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpic/html/msdn_servrapp.asp
    4. UNBUFCPY, SOCKSRV – Microsoft Platform SDK IOCP 윈속 예제 프로그램
    5. Windows Sockets 2.0: Write Scalable Winsock Apps Using Completion Ports - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnmag00/html/Winsock.asp

  • 2007/09/16 17:58 2007/09/16 17:58


    [원문] http://egofly.tistory.com/374

    아...나도 일본어 잘 하고 싶다...

    ==============================================================


    1. 사랑이란... 아이!부끄러워 말을못하겠네 사랑→아이(あい)
    2. 에! 그림은 이렇게 그리는겁니다 에헴! 그림→에(え)
    3. 우리 조카녀석은 오이만 좋아해서...... 조카 →오이(おい)
    4. 당신얼굴 보기싫어 나는 가오 얼굴→가오(かお)
    5. 여름만되면 나쪄죽네! 여름→나츠(なつ)
    6. 옛날사람들은 된장만 봐도 미소를 짓는데 요즘애들은 김치도 않먹는다니
    된장→미소(みそ)
    7. 가방은 그냥 가방이지요 가방→가반(かばん)
    8. 사슴은 무척 싯가가 비싸데요. 사슴은 → 시까(しか)
    9. 곰은 고구마를 좋아할걸..... 곰은 → 쿠마(くま)
    10. 말이 우마차를 몰고 가니까. 말은 → 우마(うま)


    11. 의자도 있습니까? 의자는 → 이스(いす)
    12. 부인이 빨래를 널러 옥상에 갔습니다 부인은 → 옥상(おくさん)
    13. 한 구치 잡았다고 입으로 크게 외쳤다. 입은 → 쿠치(くち)
    14. 다방에서 차 한잔하니 킷사 땡이로구나. 다방은 → 킷사땡(きっさてん)
    15. 코는 몇개입니까? 하나입니다. 코는 → 하나(はな)
    16. 후유- ! 또 추운 겨울이구나. 겨울은 → 후유(ふゆ)
    17. 전화 벨이 댕와! 하고 울렸다. 전화는 → 댕와(でんわ)
    18. 재떨이 줄테니까,한대피고 어이! 자라. 재떨이는 → 하이자라(はいざら)
    19. 체중은 자전거로 지탱하세요, 자전거는 → 지땐샤(じてんしゃ)
    20. 휴일인데 집에는 우찌 있습니까? 집은 → 우치(うち)


    21. 이 전차에는 댄서가 타고 있다. 전차는 → 댄샤(でんしゃ)
    22. 주시는 김에 사전도 주쇼. 사전은 → 지쇼(じしょ)
    23. 연필은 앰(M)자와같이 삐죽하게 깍으세요. 연필은 → 앰삐츠(えんぴつ)
    22. 고양이는 내꺼야. 고양이는 → 내꼬(ねこ)
    23. 개는 이를않닦아서 이가 누렇다. 개는 → 이누(いぬ)
    24. 표가 많이 있어서 기쁘다. 표는 → 킵뿌(きっ ぷ)
    25. 요즘 신문은 신분을 보장해 줄까? 신문은 → 심붕(しん ぶん)
    26. 우산 없으면 가서사 우산은 → 카사(かさ)
    27. 학생들이여! 자기자신을 잘 가꾸세. 학생은 → 가꾸세(がくせい)
    28. 책상 위에서 축구하면 않되지. 책상은 → 츠꾸에(つくえ)
    29. 오 - ! 내 키보다 크구나 크다는 → 오-끼- (おおきい)
    30. 작으니까, 치아사이에 들어가지. 작다 → 치-사이(ちいさい)


    31. 인형도 있는교? 인형은 → 닌교-(にんぎょう)
    32. 이 수첩은 태초에 만들어진 것이다. 수첩은 → 테쵸-(てちょう)
    33. 웃도리는 우와기, 웃도리는→우와기(うわぎ)
    34. 이 자동차에는 지도자가 타고 있다.
    자동차는→지도-샤(じどうしゃ)
    35. 최초의 한글소설인 책은 홍길동전이다. 책은 → 홍(ほん)
    36. 동물원에 부츠 신고 갔습니다(물릴까봐) 동물원은→도부츠엥(どうぶつえん)
    37. 회사원인 조카가 이사가 됐다. 회사원은→카이샤잉(かいしゃいん)
    38. 타바꼬 입뽕 쿠다사이. 담배는→타바꼬(たばこ)
    39. 한국인 무당은 칼 꽂고 징을 친다. 한국인은→캉꼬꾸징(かんこくじん)
    40. 이 만년필은 만년동안 히트쳤습니다. 만년필은→만넹히츠(まんねんひつ)


    41. 비행기밖은 히끗히끗 안개가 끼어있다. 비행기는→히꼬-끼(ひこうき)
    42. 비누 세개 주세요. 비누는 → 셋껭(せっけん)
    43. 잡지위에 잣씨가 있으니 먹으세요. 잡지는 → 잣씨(ざっ し)
    44. 선풍기는 바람을 세게뿜어내는기계 선풍기는 → 샘뿌-끼(せんぷうき)
    45. 안경 쓰고 두메가네, 안경은 → 메가네(めがね)
    46. 튀김은 댐뿌라, 튀김은 → 댐뿌라(てんぷら)
    47. 우체국에 가서 우편꽂고 오겠습니다. 우체국은→유-빙꼬꾸(ゆうびんきょく)
    48. 은행에 조깅코스가 없는 것이 당연하지, 은행은 → 깅꼬-(ぎんこう)
    49. 공원에 가서 코를 앵~하고 풀면 경범죄. 공원은 →코-앵(こうえん)
    50. 형은 학교 갔고 나는 집에 있습니다. 학교는 → 각꼬(がっこう)


    51. 지금 역에 간다니, 에끼! 이사람. 역은 → 에끼(えき)
    52. 배가 후내 후내 흔들리면서 간다. 배는 → 후내(ふね)
    53. 도깨비도 시계차는세상! 시계는 → 도께이(とけい)
    54. 이것은 고래심줄보다 더 질기다. 이것은 → 코레(これ)
    55. 그것은 소래라고 그냥외워라! 그것은 → 소레(それ)
    56. 저것은 저 책상 아래에 있습니다. 저것은 → 아레(あれ)
    57. 어느것이냐, 도레미파솔라시도. 어느것은 → 도레(どれ)
    58. 연필은 앰(M)자와 같이 삐쪽하게 깍으세요 연필은 → 앰삐츠(えんぴつ)
    59. 잘싸둔컴퓨터는 와~푸노! 워드프로세서→ワ-プロ
    60. 난 무엇입니까. 무엇입니까→난데스까(なんですか)


    61. 더러운휴지는 거미보다 더럽다. 휴지 →고미(ごみ)
    62. 머리에 이고 가다. 가다는 → 이꾸(いく)
    63. 굴러 오다. 오다는 → 쿠루(くる)
    64. 미루어 보다. 보다는 → 미루(みる)
    65. 연필 갖고 쓰다. 쓰다는 → 카꾸(かく)
    66. 하나씩 하나씩 이야기하다. 이야기하다는 → 하나스(はなす)
    67. 도로 집다. 집다는 → 토루(とる)
    68. 지이미 너무 수수하다. 수수하다는 → 지미다(じみだ)
    69. 오이씨는 맛있다. 맛있다는 → 오이씨-(おいしい)
    70. 술을 너무 마셨다. 마시다는 → 노무(のむ)


    71. 라디오를 키고 듣다. 듣다는 → 키꾸(きく)
    72. 소개 해 주세요. 쇼-까이 해 주세요. 소개는 → 쇼-까이(しょうかい)
    73. 왔다, 왔다, 내가 왔다. 나는 → 와따시(わたし)
    74. 이 선생님은 센세이션을 불러일으켰다. 선생은→센세-(せんせい)
    75. 억울한일은 방송에 호소해야...... 방송→호-소-(ほうそう)
    76. 대학생은 다이각세-. 대학생은→다이각세-(だいがくせい)
    77. 인사는 와이샤츠입고 해야지, 인사는→아이사츠(あいさつ)
    78. 낮에는 콘 있지 와. 낮인사→콘니치와(こんにちは)
    79. 밤에는 금방 와야돼요. 밤인사→콤방와(こんばんは)
    80. 헤어질 때는 사고 나라. 헤어질때인사→사요-나라(さようなら)


    81. 미안할 때는 → 스미마생, 미안합니다→스미마생(すみません)
    82. 실례는 → 시츠레-. (しつれい) 실례합니다는→시츠레-시마스(しつれいします)
    83. 플리-즈 도-조, 플리-즈는 → 도-조(どうぞ)
    84. 예는 → 하이,(はい) 아니오는 → 이-에(いいえ)
    85. 잘 먹겠습니다. 이따가 또 먹겠습니다.
    잘먹겠습니다는→이따다끼마스(いたたきます)
    86. 잘 먹었으니까, 고치소 사마귀를 잘 먹었습니다는→고치소-사마(こちそうさま)
    87. 그러면, 데리고 와 주세요. 그러면은 → 데와(では)
    88. 그과장님 복사를 코피나게시키네! 복사 코피-(コピ-)
    89. 춤추는모양이 오돌오돌 떠는것같다. 춤추다 오도루(おどる)
    90. 에비! 뱀나올라! 뱀 헤비(へび)


    91. 예, 그렇습니다, 소입니다. 그렇습니다는 → 소-데스(そうです)
    92. 봐라! 장미에도 가시는 있어 장미→바라(ばら)
    93. 노트는 노-또, 노트는 → 노-또(ノ-ト)
    94. 세타는 세-타, 세타는 → 세-타(セ-タ)
    95. 내 모자를 보시오. 모자는 → 보-시(ぼうし)
    96. 넥타이는 네꾸따이, 넥타이는 → 네꾸따이(ネクタイ)
    97. 어느분이냐, 또 나타난 사람이. 어느분은 → 도나따(どなた)
    98. 웃도리는 우와기, 웃도리는 → 우와기(うわぎ)
    99. 이 치솔에는 하! 브라시가 달려 있네. 치솔은 → 하브라시(はぶらし)
    100. 어머 이물건 무겁네! 무겁다 오모이(おもい)


    101. 일본에 가니 홍차를 많이 마시더라, 일본은 → 니홍(にほん)
    102. 제일 가벼운건 가루 가볍다 가루이(かるい)
    103. 차는 쿠루마, 차는 → 쿠루마(くるま)
    104. 그럼 쟈, 그럼 → 쟈(じゃ)
    105. 네 남편은 코가 오똑하지? 남편 옷또(おっと)
    106. 영국이기에 리스산업이 발달했다. 영국은 → 이기리스(イギリス)
    107. 중국인이 고추먹고 고꾸라지다 징에 맞았다. 중국인은→츄고꾸징(ちゅうごくじん)
    108. 무슨 난리가 났노. 무슨은 → 난노(なんの)
    109. 에고 에고 영어는 역시 어렵구나. 영어는 → 에-고(えいご)
    110. 친구도 모두다 친척같이 지낸다. 친구는 → 토모다치(ともたち)


    111. 사과는 서부극에 나오는 링고스타가 잘 먹는다. 사과는 → 링고(りんご)
    112. 몇개는 입구에 처 박아 놓았다. 몇개는 → 이꾸츠(いくつ)
    113. 날짜에는 하루도 있다. 있다는 → 아루(ある)
    114. 위는 우에라고도 해요. 위는 → 우에(うえ)
    115. 너희동네에선 요즘 무엇이 나니? 무엇은 → 나니(なに)
    116. 나까무라는 안에 있다. 안은 → 나까(なか)
    117. 곁에 있는 아가씨는 참으로 소박하구나. 곁은 → 소바(そば)
    118. 귤이 밀감이고 밀감은 미깡이다. 귤은 → 미깡(みかん)
    119. 아래에 있는 귤은 시다. 아래는 → 시다(した)
    120. 힌트 하나 또 주세요. 하나는 → 히또츠(ひとつ)


    121. 둘 하면 후다닥 뛰어라. 둘은 → 후따츠(ふたつ)
    122. 마누라가 셋이라니 나 미쳐! 세개는 → 밋츠(みっつ)
    123. 요강이 네개 있으니, 네개는 → 욧츠(よっつ)
    124. 이 아이는 다섯살에 이가 났다, 쯧쯧. 다섯개는 → 이츠츠(いつつ)
    125. 무우 여섯개 주세요. 여섯개는 → 뭇츠(むっ つ)
    126. 아이 일곱은 나놓자(첫날밤약속) 일곱개는 → 나나츠(ななつ)
    127. 네개는 욧츠고 여덟개는 얏츠다. 횟갈리지 말것. 여덟개는 → 얏츠(やっつ)
    128. 코코코코 도깨비코는 아홉개. 아홉개는 → 코코노츠(ここのつ)
    129. 토끼가 열마리나 있다. 열개는 → 토-(とお)
    130. 옆에서도 나리나리하고 놀고 있다. 옆은 → 토나리(となり)


    131. 회사가 이사갔습니다. 회사는 → 카이샤(かいしゃ)
    132. 병원차가 뵤-잉하고 달려 간다. 병원은 → 뵤-잉(びょういん)
    133. 파출소에서 코박고 벌서고 있다. 파출소는 → 코-방(こうばん)
    134. 옆에 있는 사람은 요구사항이 많다. 옆은 → 요꼬(よこ)
    135. 여관에서 료금않내면 강제로 쫒겨나요. 여관은 → 료깡(りょかん)
    136. 물고기 사가나 뭘 사가나 ! 물고기는 → 사까나(さかな)
    137. 야채가게에서 고양이가 야오야오하고 운다. 채소가게는 → 야오야(やおや)
    138. 둘사이에는 반드시 아이가 생긴다. 사이는 → 아이다(あいだ)
    139. 약 먹으라고 구슬리니까 잘 먹는다. 약은 → 쿠수리(くすり)
    140. 이마는 앞에있지요?. 앞은 → 마에(まえ)


    141 민원실은 민간인이 많이 찾아요. 민원실은→민간시쯔(みんがんしつ)
    142. FAX는 상대방으로 확스치며 들어가요 FAX는 → 확스(ファックス)
    143. 요즘 잘나가는 김지호는 지방사람인가? 지방은 → 지호(ちほう)
    144. 구토하는소리"하쿠" 구토는 → 하쿠(はく)
    145. 눈중에서 매눈이 제일무서워요 눈 은 → 메(め)
    146. 뜨거운불에 손데다. 손 은 → 데(て)
    147. 새아씨의 버선발이 제일 예뻐요. 발은 → 아시(あし)
    148. 딴건 참아도 엉덩이시린건 못참아!. 엉덩이는→시리(しり)
    149. 헤-배꼽빠진사람처럼 웃지마! 배꼽은 → 헤소(へそ)
    150. 파란하늘 맑은 햇살! 아오졸려! 푸른하늘→ 아오조라(あおぞら)


    151. 왜 인간이 원숭이처럼 살우? 원숭이는 → 사루(さる)
    152. 사루(원숭이)는 도망도 잘가요 떠나다도 → 사루(さる)
    153. 상좀 주쇼! 상은 → 주쇼(じゅしょう)
    154. 기분은 기모찌(きもち)니까 야한기분→야키모치(やきもち)
    155. 중요한것을보면 "어머나!"하고 놀라죠. 중요한 → 오모나(おもな)
    156. 이렇게 적게주시다니.....우수워요 적다 → 우수이(うすい)
    157. 나무는 사람보다 키가커요 나무 → 키(き)
    158. 유서도 이서해주나요? 유서 → 이쇼(いしょ)
    159. 돈벌러 가네 돈은 → 카네(かね)
    160. 한국에서는 머슴애가 아들인데...... 딸은→ 무수메(むすめ)


    161. 담배는 "수우"하고 들이키는맛! 피우다→수우(すう)
    162. 가스는 빌릴수 없지..... 빌리다→가스(かす)
    163. 아빠도 찌찌가 있어요? 아빠 →치치(ちち)
    164. 하하 벌써 네가 엄마가 되었다니...... 엄마 →하하(はは)
    165. 다시가서 확인해봐! 확인하다→타시카메루(たしかめる)
    166. 감까기! 떫으니까 까서 먹어야지 감 →카키(かき)
    167. 그남자는 카레를 좋아한데나..... 그남자 →카레(かれ)
    168. 스키타러 가래..... 가레→스키(すき):삽모양의농기구
    169. 에미야 게다가 선물까지....고마워 선물 →오미야게(おみやげ)
    170. 오래된 청자는 새지않니? 청자→세이지(せいじ)


    171. 나를 들들 보꾸지마 나→보쿠(ぼく)
    172. 싣고가는게 노루아냐? 싣다→노루(のる)
    173. 제집가는길도 잊다니..미치겠군 길→미치(みち)
    174. 나마리야 충청도 사투리써 사투리→나마리(なまり)
    175. 버리려다 아까워 도루 집었어 집다→도루(とる)
    176. 탁탁거리구 싸우면 않돼 싸우다 →타타카우(たたかう)
    177. 네땅보다 내땅이 더비싸지 값 →네당(ねだん)
    178. 하~ 이아픈건 못참아 이 →하(は)
    179. 강가에 앉아서 로뎅을 생각한다. 생각하다→강가에루(かんがえる)
    180. 감기에 가제붙인다고 났냐? 감기는 →가제(かぜ)


    181. 너의 얼굴이 보기싫어 가오. 얼굴은 → 가오(かお)
    182. 연못에서 낚시나하고 있게! 연못은 → 이케(いけ)
    183. 연말이라 보신각 종치러가네 종 → 카네 (かね)
    184. 그놈 또 화투 하나부다. 화투는 → 하나후다(はなふだ)
    185. 해물은 내장이 와따! 내장은 → 와타(わた)
    186. 로푸에 바짝매어 팔려가는 당나귀 당나귀는 → 로바(ろば)
    187. 철조망으로 막혀있지 봐 저게 목장이야. 목장은 → 마키바 (まきば)
    188. 문닫어임마! 다녀온지가 언젠데...... 다녀왔어요→다다이마(ただいま)
    189. 남이야 술집에 가던말던 술집은 → 노미야(のみや)
    190. 거짓이니까 나는 웃소 거짓말은 → 우소(うそ)


    191. 다치워 버스는 지나갔어! 지나다 → 다츠 (たつ)
    192. 껌은 씹는거야 무는 것이 아니라..... 물다 → 카무(かむ)
    193. 오오우! 덮치면 큰일! 덮다 →오오우(おおう)
    194. 옥이는 부채춤을 잘 춘다지 부채 → 오우기 (おうぎ)
    195. 나는 서투르니까 네가대신해라. 서투르다→니가테(にがて)
    196. 신호위반이면 신고하세요 신호는 → 신고 (しんごう)
    197. 오유 뜨거워! 뜨거운물 → 오유(おゆ)
    198. 이글자는 모지?. 글자는 → 모지(もじ)
    199. 더노세요 즐겁게...... 즐겁다→다노시이(たのしい)
    200. 하이쿠! 일본詩는 더어려워 일본詩→하이쿠(はいく)


    201. 누렇게 칠하면 돼 칠하다→누루(ぬる)
    202. 싫어! 가! 백발이 좋은사람은 없겠죠. 백발은 →시라가(しらが)
    203. 아야! 하지 마러유 실수한거니까 실수하다→아야마루(あやまる)
    204. 오! 또 묻혔어? 기저귀→ 오무츠(おむつ)
    205. 미세미세 밀어주세! 장사번창하도록 가게 → 미세(みせ)
    206. 다케라 모든보물 보물은 → 다카라모노(たからもの)
    207. 오모야! 야한일이 안채에서 안채 → 오모야(おもや)
    208. 우칼까유(어찌할까유) 묻다 → 우카가우(うかがう)
    209. 칼은 위험하니까 같다놔! 칼은 → 카타나(かたな)
    210. 유적을 도굴한놈은 이새끼 유적 → 이세키(いせき)


    211. 경치좋은곳에 쉬한놈은 개새x 경치 →게시키(けしき)
    212. 장례식날 춤추는놈은 소x끼 장례식은 →소시키 (そうしき)
    213. 결혼식은 결혼식→게콘시키(けっこんしき)
    214. 우박떨어지는 소리"효-" 우박 → 효우(ひょう)
    215. 너는 떡국이 좋으니? 떡국 →조우니(ぞうに)
    216. 술은 내가 사께. 술 → 사케(さけ)
    217. 오! 사나이로서는 아직어려 어리다 → 오사나이(おさない)
    218. 이길은 넘어가는 코스야 넘다 → 코스(こす)
    219. 쓸모없는 실이라구 마구 감지마라 감다 → 마쿠(まく)
    220. 고놈이 딴여자와 좋아지낸다구? 좋아함 → 고노미(このみ)


    221. 이제 그만 다니고 가요우 다니다 → 가요우(かよう)
    222. 우매 맛있는거 맛있다 → 우마이(うまい)
    223. 그병은 다고쳐서 나았습니다. 고치다→ 나오스(なおす)
    224. 나야뭐 고민이 없어서 고민이지.... 고민하다→나야무(なやむ)
    225. 여자에겐 요리보다 귀찮은건 없지 ~보다→~요리(より)
    226. 타오르니까 무너지지 무너지다→타오레루(たおれる)
    227. 아이만 남겨놓고 쓰러지다니...... 남기다 →노코스(のこす)
    228. 사랑하는 사람과 bye-bye하는 경우...... 경우 → 바아이(ばあい)
    229. 하! 이리루 들어가는 수밖에...... 들어가다는 → 하이루(はいる)
    230. 오! 멋져 이장난감 사줘요 장난감→오모챠(おもちゃ)


    231. 고추는 요령(설명못함) 요령은 → 고츠(こつ)
    232. car! 에라 바꾸자 티코로...... 바꾸다 → 가에루(かえる)
    233. 얼레꼴레 이것저것 다보이네. 이것저것→ 아레코레(あれこれ)
    234. 후미진 모퉁이는 산기슭 산기슭→ 후모토(ふもと)
    235. 돈은 모아서 개같이쓰면 않돼요 돈을벌다→모우케루(もうける)
    236. 이쁘게 부를때는 요보 부르다 → 요부(よぶ)
    237. 마누라는 뇨보 마누라 → 뇨보(にょうぼう)
    238. 쿡쿡 루푸로 묶으면 않풀려 묶다 → 쿠쿠루(くくる)
    239. 비오는날 세차해야 도로 진흙투성이 진흙 → 도로 (どろ)
    240. 우엥! 그것보오 우엉 → 고보우(ごぼう)


    241. 구름을 몰아왔으니까 흐리게하다 → 구모라스(くもらす)
    242. 오! 소름끼쳐 공포심→오소레(おそれ)
    243. 아이를 업을 때 "오부우-". 업다 → 오부우(おぶう)
    244. 아야말우 사과할테니까...... 사과하다 → 아야마루(あやまる)
    245. 누구 닦아줄 사람없소? 닦다 → 누구우(ぬぐう)
    246. 여자는 고무신, 남자는 우와기를 바꿔입으면 외도,첩→우와끼(うわき)
    247. 하루까 이틀일까 아뭏튼 까마득한날에 까마득한→하루카(はるか)
    248. 그놈 모자쓰고 까부러 쓰다→카부루(かぶる)
    249. 부츠신고 때리면 최소한 사망 때리다 → 부츠(ぶつ)
    250. 올빼미는 부끄러워 밤에만 다닌다. 올빼미→후꾸로우(ふくろう)


    251. 악어가 왔니? 도망가자.. 악어 → 와니 (わに)
    252. 꿩이 기지개를펴면 잡기어려워 꿩은 →키지(きじ) ,やけい라고도함
    253. 무의식 중이라고 "뭐 이세키!"하면않돼 무의식 →무이시키(むいしき)
    254. 이세상에 미미한 동물은 지렁이다. 지렁이는 → 미미즈(みみず)
    255. 미미즈를 쿡! 먹는놈은 부엉이다. 부엉이 → 미미즈쿠(みみずく)
    256. 추어탕 맞있어요 더줘요 미꾸라지→ 도죠우(どじょう)
    257. 찌찌만 붙잡고 사는사람의 약자. 유방 → 치부사(ちぶさ)
    258. 지지면 오그라들게 마련 오그라들다 치지무(ちぢむ)
    259. 나이를 먹으면 수염도 희게된다. 수염은 → 히게(ひげ)
    260. 계층적인 단계 단계 케타(けた)


    261. 뇌는 no(없는사람 없어요) 뇌는 → 노(のう)
    262. 시험봐서 죽쑨사람 가는곳 사설학원→주쿠(じゅく)
    263. 집지을땐 기둥부터 세우게 하시라! 기둥 하시라(はしら)
    264. 얼마나 때렸으면 저렇게 나구루?. 때리다→나구루(なぐる)
    265. 여기서 자리? 미친x아! 자갈길은 →자리미치(じゃりみち)
    266. 썰매타는 소리? 썰매 → 소리 (そり)
    267. 기업의 성공도 기교가 있어야 기업은 →기교- (きぎょう)
    268. 아이 부끄러워..... 애무 → 아이부(あいぶ)
    269. 아이구 숨차 숨차다 → 아에구(あえぐ)
    270. 총각에게 아가씨는 등불이나 다름없죠 등불은 → 아카시(あかし)


    271. 오! 도깨비는 밖에 있데요 도께비 → 오바케(おばけ)
    272. 다 놓고 물러가다. 물러서다 → 노쿠(のく)
    273. 아지랑이 펴오르면 가슴이 두근두근 아지랑이,안개→가스미(かすみ)
    274. 그 파초좀 파쇼 파초는 → 바쇼(ばしょう)
    275. 두릅은 산에가서 따라 두릅 → 타라(たら)
    276. 이것은 꼭 알아야죠(꽂중에 kinger) 무궁화→킹카(きんか)
    277. 물이 "좌-"하고 나오는 꼭지 수도꼭지→자구치(じゃくち)
    278. 분기점이 생기도록 마구 구기리 분기점 → 쿠기리(くぎり)
    279. 고자에겐 있으나마나 돛자리→ 고자(ござ)
    280. 홀아비에겐 고게 최고 과부는 → 고케(ごけ)


    281. 향나무밑에서 코박구 서는벌이 제일 힘들어 향나무→코우보쿠(こうぼく)
    282. 동물의 교미도 흥미는 있게 마련 흥미 → 교미(きょうみ)
    283. 매를 맞으면 무지 아파요 매 → 무치(むち)
    284. 토끼가 달따오기 놀이를 한다 따오기 →토키(とき)
    285. 추석날밤의 달은 오봉(쟁반)같대요 추석 → 오봉(おぼん)
    286. 바뀌어라 얏! 둔갑하다 → 바케루(ばける)
    287. 새끼줄로 묶어서 끌고나와! 밧줄 → 나와(なわ)
    288. 흙은 지지야 흙은 → 츠치(つち)
    289. 사또의 건강을묻는 전화가 쇄도한다 쇄도 → 삿토우(さっとう)
    290. 너 이젠 관둬! 인연을 끊는거야 인연을끊다→간도우(かんどう)


    291. 갈대의 멋을 아시나요 갈대는 → 아시 (あし)
    292. 예쁜색시도 부르면 올꺼야 포주집은 → 오끼야(おきや)
    293. 추우면 귀찮아서 요강에다 "쉬-" 오한 → 오캉(おかん)
    294. 우서리는 잔돈이야! 잔돈 → 오츠리(おつり)
    295. 귀신은 밤에만 오니? 귀신 → 오니(おに)
    296. 어려워도 가만히 참고 견뎌봐 참고견딤→가만 (がまん)
    297. 낫들고 벌초하러 가마 낫은 → 카마(かま)
    298. 오 신이시여 미끼는 아니니 한잔쭉...... 신에게 바치는술 → 오미끼(おみき)
    299. 일본어 공부도 하다가 마나부네! 배우다→마나부(まなぶ)
    300. 그선수 무척 센데 선수→센테(せんて) : 먼저수를놓음
    301) 저안경테는 금부치로 만들었네 금테 → 킴부치 (きんぶち)
    302) 그림이 그려진 무명옷감 참멋져 사라사 그림이있는무명옷감→사라사(サラサ)
    303) 거지같은 행색을 한것을보니 고아인모양이지? 고아 → 고지 (こじ)
    304) 조새끼는 상식도 없는 놈이야 상식 → 조시끼 (じょうしき)
    305) 야! 가만히 있어! 시끄럽다니까 시끄럽다→야카마시이 (やかましい)
    306) 처마끝에 고드름이 주루루 매달렸네 고드름 → 츠라라 (つらら)
    307) 하마가 자고 있어 가봐 하마 → 카바 (かば)
    308) 꼬마들이 즐기는 놀이는 팽이치기지 팽이 →코마 (こま)
    309) 가축을 기르려면 들판에 놓아라 들판 →노하라 (のはら)
    310) 태양에 가까이가면 타요 태양 → 타이요우 (たいよう)


    311) 요즘 북한에선 보리도 무기가 될수 있어 보리 → 무기 (むぎ)
    312) 동료들의 모임이라면 나가마 동료 → 나카마 (あかま)
    313) 새끼줄로 묶어서 끌고나와 새끼줄 →나와 (なわ)
    314) 하리핀은 바늘이라는 일본어야 바늘 → 하리 (はり)
    315) 야매루 하지말고 그만둬! 들통난다고! 그만두다 →야메루 (やめる)
    316) 매를 맞으면 무지 아퍼 매, 채찍 →무치 (むち)
    317) 사위놈 행동이 저게 무꼬? 사위 →무꼬 (むこ)
    318) 아차 실수하면 멍들어 멍 →아자 (あざ)
    319) 쭉-가레 피곤해 죽겠는데... 피곤 → 츠카레 (つかれ)
    320) 옷을 벗으니까 누구인지 알수 없네 벗다 → 누구 (ぬぐ)


    321) 관둬! 오늘부터 인연을 끊은거야 인연을 끊다→칸도우 (かんどう)
    322) 싱거우면 소금을 넣으시오 소금 → 시오 (しお)
    323) 사루마다가 팬티라는 것 다알죠? 팬티 →사루마타 (さるまた)
    324) 물건을 팔려면 "사소"하고 유혹해야죠 유혹하다 → 사소우 (さそう)
    325) 오우라이! 스톱!은 길거리에서 흔히볼수있죠 길거리 →오우라이 (おうらい)
    326) 무꾸 (무우의 사투리)는 까야 먹지 까다 →무꾸 (むく)
    327) 말탈때는 가랭이를 벌려야 가랭이 → 마타 (また)
    328) 하루에 갈수 없는 까마득한 거리 까마득한 → 하루카 (はるか)
    329) 가오리회가 맛있다더니 에이! 별거아니군 가오리 → 에이 (えい)
    330) 가위 -바위 -보 는 잘알죠? 가위바위보→장켕 (じゃんけん)


    331) 곰은"쿠마"손은"데"그러니까갈퀴는 곰의손과 같다 갈퀴 →쿠마데 (くまで)
    332) 개미에게 물리면 아리다 개미 →아리 (あり)
    333) 곡식중에 제일 꼬마는 "깨" 깨 → 고마 (ごま)
    334) 걸레도 빨겸 조깅도 할겸 일거양득이어요 걸레 →조우낑 (ぞうきん)
    335) 게는 옆으로 가니? 게 →카니 (かに)
    336) 겐세이 놓지말구 네일이나 잘해 견제 → 켄세이 (けんせい)
    337) 산불나면 계곡도 타니? 계곡 → 타니 (たに)
    338) 다슬기는 니나 먹어라 다슬기 →니나 (にな)
    339) 걷기힘드니까 뭐라도 타고가요 탈것→가요(がよ)
    340) 나밉다고 서러워 눈물 흘리지 마라 눈물 →나미다 (なみだ)


    341) 에라이 나쁜놈 제사진이 훌륭하다고? 훌륭하다 →에라이 (えらい)
    342) 얼음도 예쁘게 조각하면 고우리 얼음 →코오리 (こおり)
    343) 아끼래두 어이없이 다써버렸네 어이없다→아끼레루 (あきれる)
    344) 이 아이가 자기아이라고 두여자가 실랑이다 실랑이 →이이아이 (いいあい)
    345) 다봐! 코로 연기가 나지? 담배 →다바코 (たばこ)
    346) 아이가 쪼금쪼금 아장아장 걷지요 아장아장→쪼코쪼코 (ちょこちょこ)
    347) 자포자기하지말고 야! 깨라 깨! 자포자기 →야케 (やけ)
    348) 유감 있어? 왜그리 삐딱하니 삐뚤어지다 → 유가무 (ゆがむ)
    349) 아오! 그름한점 없네 하늘좀 쳐다봐! 쳐다보다 → 아오구 (あおぐ)
    350) 어이할꼬 부모와 자식이 다 쫒아왔으니... 부모와 자식→오야코 (おやこ)


    351) 갓난아이보고 새끼씨라고 갓난아이 →세끼시 (せきし)
    352) 값이 내려가면 사가리... 내려감 →사가리 (さがり)
    353) 반반씩 나누어 하면 충분히 할수 있어 충분히 →반반 (ばんばん)
    354) 얼룩말이야 한번봐 얼국말 →한바 (はんば)
    355) 수래를 끄는말도 "밤바"하고해(차앞부분) 수래를끄는말 →밤바 (ばんば)
    356) 지명하기전에 나 자수할래 지명하다 →나자스 (なざす)
    357) 할아버지 수염은 희게 마련이죠 수염 → 히게 (ひげ)
    358) 우-하고 다 모여서 계를 하는것 같은 잔치 잔치 →우타게 (うたげ)
    359) 이 구멍은 왜 뚫었는지 자네는 아나? 구멍 →아나 (あな)
    360) 고개길은 힘드니까 내가 도울께 고개 →토우게 (とうげ)


    361) 발음이 비슷해요 주춤 →추쵸 (ちゅうちょ)
    362) 가스도 찌꺼기가 있나 찌꺼기 →카스 (かす)
    363) 불구자에게 "갔다와?"라고시키면 되나! 불구 → 카타와 (かたわ)
    364) 바로 옆이니까 갔다와라 바로옆 →카타와라 (かたわら)
    365) 가시나무는 비슷해요 가시나무 →카시 (かし)
    366) 해가 났다! 해났다 양지 →히나타 (ひなた)
    367) 요즘 배꼽티의 매상이 호조를 이루죠 배꼽 →호조 (ほぞ)
    368) 울으면 눈가에 물기가 서려요 물기를머금다→우루무 (うるむ)
    369) 어차피 도울거라면 지금 도우세 어차피 →도우세 (どうせ)
    370) 빵은 앙코가 제일좋고 여자는 처녀가... 처녀 →앙코 (あんこ)


    371) 대머리는 가발을 갖추라 가발 →카츠라 (かつら)
    372) 은행나무는 어디가나 있죠 은행나무→잇쵸 (いちょう)
    373) 간질러도 못느끼는 사람은 없을껄 느끼다 →칸지루 (かんじる)
    374) 지신(땅의 귀신)이 지진을 일으키나와 지진→지신 (じしん)
    375) 그 음식은 보기좋고 더구나 맛있데 더구나→마시테 (まして)
    376) 대머리는 가발을 갖추라. 가발→카추라 (かつら)
    377) 줄래 못줄래 다투면 갈등만 커져요. 갈등→모추레 (もつれ)
    378) 조게 상하를 따져? 버릇없이.. 상하→조게 (じょうげ)
    379) 야야! 조금만 힘을내. 조금→야야 (やや)
    380) 깐건데 다시까니? 확실하군. 확실히→타시카니 (たしかに)


    381) 가만히 있어! 참으라구. 참다→가만 (がまん)
    382) 남을 조롱하면 나쁘리. 조롱함→나부리 (なぶり)
    383) 야마시는 알지요. 사기꾼이라는것. 사기꾼→야마시 (やまし)
    384) 이모가유∼고구마죽 만들어줬씨유∼ 고구마죽→이모가유 (いもがゆ)
    385) 임마! 임마! 씨이! 분해죽겠네! 분하다→이마이마시이(いまいましい)
    386) 이데루 얼어버리면 안돼. 얼다→이테루 (いてる)
    387) 얼마후에 떠나면 그만이지 잊으래. 얼마후→이즈레 (いずれ)
    388) 사자보고 시시하다니. 사자→시시 (しし)
    389) 유도리는 아시죠. 여유→유토리 (ゆとり)
    390) 나쁜소문이지만 얼마나 웃기나 나쁜소문→우키나(うきな)


    391) 배위에서 잠든꼴은 더 웃끼네 배위에서잠→우키네(うきね)
    392) 아쿠! 다날라오네 먼지가.... 먼지→아쿠다(あくた)
    393) 아빠아빠! 그건엄마원피스야! 입으면않돼 원피스→압팟파(あっぱっぱ)
    394) 화투판에서 쇼당! 상담→소우당(そうたん)
    395) 화투판에서 기리! 끊기→키리(きり)
    396) 당구장에서 오시! 밀기→오시(おし)
    397) 당구장에서 히끼! 끌기→히키(ひき)
    398) 당구장에서 시로! 흰색→시로(しろ)
    399) 남을 괴롭히면 나쁘리.... 괴롭힘→나부리(なぶり)
    400) 나리! 모양이 별로 좋지않사옵니다. 모양,형상→나리(なり)


    401) 독가스가 살포되면 다른곳으로 옮겨야 옮기다→도카스(どかす)
    402) 지시는 발음만 바꾸면 돼요 지시→시지(しじ)
    403) 큐우슈우는 섬이라 바다물도 흡수한다 흡수→큐우슈우(きゅうしゅう)
    404) 내리는 눈을 후-하고 불면 기차게 날아간다 눈보라→후부키(ふぶき)
    405) 갖고도 않가진체 숨겨두다→카코우(かこう)
    406) 아유! 눈부신 저고기는 은어라구 한데 은어→아유(あゆ)
    407) 검소는 싫소(그래도 경제는 살려야) 검소→싯소(しっそ)
    408) 아뭏튼 나는 니가 싫어 아무튼→나니시로(なにしろ)
    409) 가다랭이란 고기가 먹고 싶으니 갖추오! 가다랭이→가추오(かつお)
    410) 간좀봐! 씨이! 향기로운가 향기롭다→칸바시이(かんばしい)


    411) 모델두 인기가 있어야지 인기있다→모테루(もてる)
    412) "자기"없는 사람을 천진하다고 해야할지..... 천진함→무쟈키(むじゃき)
    413) 쓰고싶어도 체념하고 아끼라메 너는왜써! 체념→아키라메(あきらめ)
    414) 불평이나 이의에 빠진사람은 구조해야죠 불평,이의→쿠조(くじょう)
    415) 지성이 없는놈이라면 아예 한방 치세 지성→치세(ちせい)
    416) 그것도 사라고 일부러 꼬드기면 않되지 일부러→코토사라(ことさら)
    417) 얼음도 예쁘게 다듬으면 고우리 얼음→코오리(こおり)
    418) 옛날의 고을도 지금의 군 군→코오리( こおり)
    419) 눈둑에서 발을 헛디디면 굴러 노둑→쿠로(くろ)
    420) 혼자 마시게 저리좀 가주 과습.쥬수→카쥬(かじゅう)


    421) 면목이 없어서 않나가려해도 자꾸 나오래 면목이없음→나오레(なおれ)
    422) 오메! 오메! 창피해라 창피함→오메오메(おめおめ)
    423) 요즘 포장지도 아끼라고 호소를 하지만 포장→호우소우(ほうそう)
    424) "하리핀"은 바늘이란는 얘기야 바늘→하리(はり)
    425) 무시무시한 벌래도 있어 벌래→무시(むし)
    426) 소쿠리하고 자루는 같은건가? 소쿠리→자루(ざる)
    427) 고래를 잡을려고 했는데"에이" 가오리가 걸렸어 가오리→에이(えい)
    428) 휴전을 하면 전쟁은 끝나는 거예요 종전→슈센(しゅうせん)
    429) 요렇게 예쁘게 손질하고 오다니 치장하다→요소오우(よそおう)
    430) 무엇을 잃었길래 그렇게 우시나요 잃다→우시나우(うしなう)


    431) 전쟁에서는"식량 내라우"하고 총으로 겨누기도한다 겨누다→네라우(ねらう)
    432) 보상을받으려면 증거자료로 사진이라도 찍어노우 보상하다→츠구나우(つぐなう)
    433) 난처음에 대추도 몰랐다 대추→나츠메(なつめ)
    434) 좋은 물건을 사려면 우리를봐 매점→우리바(うりば)
    435) 가치는 우리말과 같아요 가치→가치(がち)
    436) 기는 독(dog)은 가엾다 가엾다→기노도쿠(きのどく)
    437) 쉬는게 아니라 죽은거요 죽다→시누(しぬ)
    438) 캬~ 구린내 냄새맡다→카구(かぐ)
    439) 어항 속의 잉어도 고이 잠들었네 잉어→고이(ごい)


    440) 양보하는 것이 좋을 것 같아요 양보→죠호(じょうほ)
    441) 기억이 않난다고변명하지말고차라리있소라고하시오 차라리→있소(いっそ)
    442) 가오리는영문의"A"자처럼 생겼대요 가오리→에이(えい)
    443) 지까지께 함부로 떠들다니 한심한 녀석 함부로→즈케즈케(ずけずけ)
    444) 압핀은 못보다 가벼워요 압핀→가뵤우(がびょう)
    445) 어머니를 무거운짐으로 여기다니불효막심한녀석 무거운짐→오모니(おもに)
    446) 웃을일이 아닌데 웃다가 왔써? 수상한테.... 수상하다→우타가와시이(うたがわしい)
    447) 그런 것은 소쿠리에 모조리 담아두어라 모조리→솟쿠리(そっくり)
    448) 미스(miss)한 꼴좀보라지 얼마나 초라한가 초라하다→미스보라시이(みすぼらしい)
    449) 교육도 효과를 얻으려면 평가를 해야 평가→효우가(ひょうか)
    450) 요거뭐야 설마 그건 아니겠지 설마→요모야(よもや)


    451) 독하게 생겼지만 독은 없어요 도마뱀→도카게(とかげ)
    452) 도구는 갈아서 만드는 거예요 갈다→토구(とぐ)
    453) 고모님 왠일로 거적을 쓰고계시나요 거적→코모(こも)
    454) 웃다가 왔지만 사실인지 의심스럽네 의심스럽다→우타가와시이(うたがわしい)
    455) 어른들은 아구찜을 앙꼬보다 맛있다고 하던데 아구→앙코우(あんこう)
    456) 아~ 많다 다수→아마타(あまた)
    457) 그물건은 안주머니에 담어 둬 안주머니→타모토(たもと)
    458) 색다른데가 있어서 이뻐요 색다르다→입뿌우(いっぶう)
    459) 발음이 비슷해요 주춤→츄쵸(ちゅうちょ)
    460) 컨닝할땐 두려움도 참고하는 거래요 참다→칸닝(かんにん)


    461) 끝까지 왔으니까 이제 스소! 끝→ 스소(すそ)
    462) 덧저고리는 어찌 하오리까? 덧저고리→하오리(はおり)
    463) 닭은 잡어서 먹어야죠 일본닭→쟈보(ちゃぼ)
    464) 웃으면 눈이 작아진다 가늘게뜬눈→우스메(うすめ)
    465) 왠지 점점 우다닥 뛰고 싶어요 점점.왠지→우타타(うたた)
    466) 발음이 비슷해요 조마조마→소와소와(そわそわ)
    467) 이사람저사람 다겨나왔으니까한창이지 한창→타케나와(たけなわ)
    468) 부모에겐 후보란 없다 부모→후보(ふぼ)
    469) 야야! 꼬시지마 횟갈려 횟갈리다→야야코시이(ややこしい)
    470) 당황한것처럼 바보짓을 하는놈은 맹구라오 당황하다→멘쿠라우(めんくらう)


    471) 독감 걸렸다고 깐보지 말어유 독감→깐보우(かんぼう)
    472) 하기싫어도 저절로 되는걸 어떻게 이를갈고잠→하기시리(はぎしり)
    473) 고새끼 말버릇 좀 보게 말버릇→고우세키(こうせき)
    474) 꼬꾸라지듯이 꾸벅꾸벅 졸고 있네 꾸벅꾸벅→콧쿠리(こっくり)
    475) 길이없어서 논두렁길로 나왔네 논두렁길→나와테(なわて)
    476) 아무리 사모한다해도 그대는 실타우 사모하다→시타우(したう)
    477) 우-하고 토하지 마시오 아무리 꺼림직해도 꺼림직하다→우토마시이(うとましい)
    478) 아마 그녀는 지금쯤 해녀가 되었을걸... 해녀→아마(あま)
    479) 너같은놈 넓은바다에 빠져 죽어도 우나봐라 넓은바다→우나바라(うなばら)
    480) 너네 이모 감자같이 못생겼더라 감자→이모(いも)


    481) 마을에서 제일 높은 사람은 사또! 마을→사토(さと)
    482) 터벅터벅 우연히 걷다가 그녀를 보았다 우연히→타마타마(たまたま)
    483) 그일은 무뎃뽀로 밀고 나가선 않돼 무턱대고→무텟포우(むてっぽう)
    484) 그사람하는 일은 유도리가 있어 여유→유토리(ゆとり)
    485) 유감이 있냐? 왜그리 삐딱해 비뚤어짐→유가미(ゆがみ)
    486) 못 믿겠어? 비벼서 꺼! 불을비벼끄다→모미케스(もみけす)
    487) 너무 바판하지 마라 그건 모독이야 비판하다→모도쿠(もどく)
    488) 싫어! 가시있는 나무는....... 가시나무→시라카시(しらかし)
    489) 사실무근인 소문이지만 왜 그리 웃끼나! 사실무근인소문→우키나(うきな)
    490) 윗층에 올라가서 조시오 윗층→죠쇼(じょしょう)


    491) 아! 좋다 신접살림은 역시 신접살림→아라조타이(あらじょたい)
    492) 넌 왜 이 자리에 계속 앉아만 있니 앉은뱅이→이자리(いざり)
    493) 오차놓고사이사이춤출정도로쉬운일손쉬운일→오차노코사이사이(おちゃのこさいさい)
    494) 어떻게 저렇게 익살을 부리니? 익살→오도케(おどけ)
    495) 오메! 오메! 염치없이 저게 뭐람 염치없이→오메오메(おめおめ)
    496) 카스(캔맥주)도 많이 마시면 잔소리가 많아진다 잔소리→카스(かす)
    497) 병원에 갔다와! 혹시 나을지 모르니까 불구자→카타와(かたわ)
    498) 술잘 먹는 사람은 좋고 호주가→죠우코(じょうこ)
    499) 술못먹는 사람은 개코 술못마시는사람→게코(げこ)
    500) 비열한 마음을 나타낼때 "개-쓰벌" 비열한마을을나타내다→게스바루(げすばる)

    2007/09/11 10:04 2007/09/11 10:04