인프런 커뮤니티 질문&답변

neohtux님의 프로필 이미지
neohtux

작성한 질문수

[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버

채팅 테스트 #2

Connect를 이용하여 여러소켓 생성후 문제점

작성

·

1.4K

0

안녕하세요 루키스님 정말 강의 도움 많이 받고 있어요 !!

소켓을 10번 생성과함께 커넥트를 요청하는 부분에
0.1초 딜레이를 주면 (*대부분*) 잘작동하더라구요

하지만, 저 딜레이를 빼면 아래 그림과같은 에러가 나와요!

저는 이것을 비동기에서 발생하는 문제점이라고 생각했습니다.


그래서 Receive에 _lock을 걸어서 실험도해봤지만
여전히 같은 오류를 내고 있더라구요

혹시 이런 에러가 발생하는 부분의 가능성이나
해결방법이 어떤게 있을까요? 딜레이를 주는경우
대부분 잘되는것은 비동기 문제가 맞는걸까요?

답변 8

1

Rookiss님의 프로필 이미지
Rookiss
지식공유자

헉 ㅎㅎ 저 부분이 문제인게 맞습니다.
세션은 무조건 연결이 맺어질 때마다 새로 만들어주거나 (Pooling이 없다면)
기존에 아무도 사용하지 않는 것을 사용해야 합니다 (Pooling이 들어간다면)

지금 하신 방법은 Session을 하나만 만들고
연결이 올 때마다 그 세션을 사용하도록 했는데
식당으로 비유하면 테이블을 하나만 지정해서
고객이 올때마다 무조건 그 테이블로 자리 배치를 시켜준 셈이 됩니다 -_-b
테이블을 공유하면 안 되는 이유와
세션을 공유하면 안 되는 이유는 사실상 같습니다.
세션에는 ReceiveBuffer라거나, 연결 Socket 정보와 같이
특정 클라에 1:1 종속적인 정보들이 있기 때문에
이를 다른 클라한테 넘겨줄 수 없습니다.

참고로 _sessionFactory.Invoke() 부분을
Func을 받지 않고 new Session()로 대체해서 생성을 해도 일단은 됩니다.
다만 그렇게 하면 나중에 PacketSession이라거나,
Session을 상속받은 다른 타입의 세션을 생성을 하는게 까다로워집니다

1

Rookiss님의 프로필 이미지
Rookiss
지식공유자

음~ 느낌상 세션은 분리가 되었는데,
어찌하다 보니 동일한 세션에 대해
Receive를 중복 호출한 것 아닐까 싶습니다. (물론 예상입니다)
세션을 1개만 만들고 Receive 부분에 BreakPoint를 건 후
여러번 걸리지 않는지 확인해보시기 바랍니다.

그리고 사람마다 생각하는 방식이 다 다르기 때문에
본인 스타일로 고쳐 보는 것은 당연히 좋습니다. (오히려 필수적 아닐까 싶네요)
참고로 저도 남의 코드를 따라치면
이상하게 머리에 잘 남는게 없어서
책에서 배운 내용은 큰 틀에서만 참고하고
다시 만들어보면서 학습하는 편입니다.

아무튼 고민해보시고 버그 해결이 안 된다 싶으면
메일로 보내주시면 되겠습니다 -_-b

1

Rookiss님의 프로필 이미지
Rookiss
지식공유자

안녕하세요,

위 문제는 비동기 문제이기는 하지만
일반적인 멀티쓰레드 비동기 문제는 아니고,
정확히는 SocketAsyncEventArgs 사용과 관련된 문제입니다.

현재 recvArgs를 ReceiveAsync의 인자로 넘겨주고 있고,
이를 이용해서 Recv 완료 통지를 받아주고 있는데요.
혹시라도 비동기 Read 작업이 완료되기 전에
recvArgs를 재사용 하면 저런 문제가 발생하게 됩니다.

Lock으로 보호한다고 문제가 해결되지 않는 이유는,
작성하신 Receive 함수를 여러 쓰레드가  동시에 호출해서 발생한 것이 아니라,
말 그대로 이전에 예약한 비동기 Read가 완료되지 않은 상태에서
다시 Receive를 시도했기 때문입니다.

강의에서는 코드의 흐름을
RegisterRecv -> OnRecvCompleted(완료 통지) -> RegisterRecv 
이렇게 호출하고 있기 때문에 비동기 Read가 완료되기 전에
해당 recvArgs를 재사용 하지 않아야 정상입니다.

그런데 위 코드에서 정확히 무엇이 문제인지는 
첨부하신 이미지로만은 판단할 수가 없는데,
혹시 SocketAsyncEventArgs를 Session끼리 공유했다거나,
재사용했다거나 하는 부분이 있을까요?
고민해보시고 원인 파악이 안되면
그냥 통으로 rookiss@naver.com로 보내주시면 확인해보겠습니다.

0

Rookiss님의 프로필 이미지
Rookiss
지식공유자

문제가 해결 되었다니 축하드립니다 ㅎㅎㅎ
기타 질문사항이 있으시다면
rookiss@naver.com로 보내주시면 되겠습니다.

0

neohtux님의 프로필 이미지
neohtux
질문자

루키스님 최고에요! ㅠㅠ 
"비슷한 에러를 경험하신 다른 분들도 이 글이 도움이 되셨으면 좋겠습니다."

"개인적으로 c# 강의 부터 들어봤는데 루키스님 강의가 너무좋아서
아직 시작은 못했지만 닷넷 코어 웹서버나, 유니티 강의도 미리 구입했어요

데이터베이스도 컴퓨터 사이언스 관련해서 공부가 필요한데
이론적으로 밖에 아직 못해서 루키스님 강의를 구입하려고해요.  

컨텐츠나 추후 오픈될 강의에 대해 루키스님께 질문을 따로 남기고싶은데
메일로 질문 드려도 될까요? " 

0

neohtux님의 프로필 이미지
neohtux
질문자

동일한 세션이 중복되어 Receive가 중복사용되는 이유를 찾은거 같습니다.
하지만 "제가 생각한 부분이 맞는지 정확히 잘 모르겠습니다." 

루키스님께서 아래 제가 생각한 원인이 맞는지 검증해주시면 감사하겠습니다 ㅠ 

아래는 루키스님처럼 Func 델리게이트를 사용하지 않은, 기존 코드입니다.

첫 번째 사진은 서버 리스너에 Session을 하나 생성하여 매개변수로 넘겨주고있습니다.

두 번째 사진은 Session _session 전역 변수가 매개변수로 전달해준 session을 참조합니다.

세 번째 사진

전역변수 _session은  Init의(IPEndPoint iPend, Session session)의 매개변수로
전달되어진 session을 가리키고 있고, 그 session의 메서드를 호출하고있습니다.

 -> Func 델리게이트를 사용하여 새로운 세션을 만들어주지 않고,
전역변수의 _session은 새로운 세션이 아닌 기존 Init으로 전달해준 session의 하나의 session 객체 주소를
참조하는 상태이고, 이 경우 만약 서로 다른 클라이언트 데이터를 Receive할때 한 객체의 session에서

중복되어 receive가 호출되는 현상이 발생할수 있다고 생각했습니다.

하지만,

Func<Session>을 이용하여 Invoke를 통해 새로 return new Session 객체가 생성되는
신규 세션은 중복된 세션이아닌 세션간 서로 다른 주소의 메모리에 위치하기 때문, 
각 여러 클라이언트들 데이터를 동시에보내도 세션마다 각자 처리 되기 떄문 중복되어 사용되어지는 경우를 피할수
있다고 생각했습니다.

이런 원인을 생각하고
인터페이스를 Func를 사용하여 새로운 세션을 만들어주는 방식으로 바꾸니 충돌되는 현상은 해결할 수 있었습니다.

추측인터라. 정확한 이유가 맞는지 루키스님께 검증을 부탁드리고싶습니다 ㅠ

0

neohtux님의 프로필 이미지
neohtux
질문자

감사합니다! 
조언해주신 부분도 고려해서 계속 디버깅해보겠습니다~
만약 Receive가 중복호출이되면 왜 중복호출이되었는지도 찾아봐야겠네요!

걷는 방식이 그래도 틀리지 않은거 같아서 다행이네요 ..

독학해오며 마음한쪽 걱정된 부분이 가벼워진 느낌입니다! :) 

0

neohtux님의 프로필 이미지
neohtux
질문자


세션끼리 공유해서 발생한 문제가 맞는거 같습니다 ㅠ 

main문안에서 

{

   for(int i=0; i<5;++i)

            {

                ServerSession session = new ServerSession();

                connector.Connect(endpoint, Instance.Generate(session));

            }

}

세션이 공유되는 부분을 고치고자
이렇게 새 세션을 생성해서 넘겨주는것도 같은 문제가 발생하더라구요 

ServerSession 객체를 생성할때마다 5개의 세션은 각각 힙에 서로 다른 메모리에 생성되는것이 아닌가요?


추가질문!)
(루키스님 강의를 보고 똑같이 따라하지 않고 최대한 수업내용을 먼저 듣고 
흐름대로  코드를 짜려다보니 좀 다르게짠부분이 꽤있더라구요 ㅠ )
q)Session이나 Send/ReceiveBuffer.cs 만 몇번을 지우고 다시 짜봐도 루키스님 코드처럼 나오진 않더라구요...
    이렇게 학습하는 방법도 괜찮을까요...? 

neohtux님의 프로필 이미지
neohtux

작성한 질문수

질문하기