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

손태정님의 프로필 이미지

작성한 질문수

Windows 소켓 프로그래밍 입문에서 고성능 서버까지!

MFC 채팅 서버와 클라이언트 (예제 포함)

질문있습니다

해결된 질문

작성

·

473

·

수정됨

0

  1. 채팅 서버 코드 상에서 쓰레드를 생성한 직후 바로 CloseHandle함수를 호출하여 쓰레드 핸들을 해제해주는 부분이 있는데 쓰레드의 동작이 완료되기 전에 CloseHandle을 해줘도 문제가 없나요??

  2. 리스닝 소켓과 accept함수로 생성된 소켓의 포트 번호가 25000으로 netstat와 wireshark 상으로 보면 동일하게 나오는데 여러 개의 소켓이 하나의 포트 번호를 공유할 수 있나요?? 아니면 netstat와 wireshark의 편의 기능인가요?? accept하면 랜덤한 포트번호를 할당받아서 소켓에 부여한다고 알고 있어서 질문드립니다 ㅠ

  3. 리스닝 소켓도 버퍼가 있나요??

  4. shutdown(hSocket, SD_BOTH);로 리스닝 소켓을 shutdown해주고 나서 accept를 해봤는데 클라이언트의 접속이 잘 되더군요. 리스닝 소켓의 shutdown은 아무런 효과가 없는 건가요??

  5. 클라이언트와 연결돼있는 상태에서 closesocket(hSocket);을 해서 리스닝 소켓을 해제해봤더니 서버에 연결돼있는 모든 클라이언트에게 RST가 보내졌습니다.
    그럼 서버가 종료될 때 클라이언트 연결을 끊으려고 모든 클라이언트 소켓들을 순회하면서 closesocket을 해주는 대신 리스닝 소켓하나만 closesocket을 해주는 방식을 써도 될까요??

답변 4

0

널널한 개발자님의 프로필 이미지
널널한 개발자
지식공유자

  1. 네, 그렇게 생각하는 것이 좋겠습니다.

  2. 어떻게 생각하면 RST에 의한 비정상 종료가 나쁘지 않을 수 있습니다. 연결과 달리 종료시에는 4-way handshake을 하기 때문에 시간이 더 걸리기 때문입니다. 문제는 각종 네트워크 관리 시스템에서 RST를 비정상 현상으로 인식한다는 것입니다. 그런 부분을 신경쓰지 않는다면 오히려 빠른 처리 방법이 될 수 있습니다.

참고하시기 바랍니다.

손태정님의 프로필 이미지
손태정
질문자

아 그럼 상황에 따라서 RST 비정상 종료가 필요할 수도 있겠네요

답변 감사합니다 :)

0

널널한 개발자님의 프로필 이미지
널널한 개발자
지식공유자

  1. 네, 문제 없습니다. 생성되고 실행된 스레드를 제어할 필요가 없다면 닫아 두는 것이 좋습니다.

  2. 리슨 소켓은 25000이며 이는 외부와 연결되지 않은 소켓입니다. 소켓에 바인드 되는 정보는 로컬 IP, Port + 리모트 IP + Port 입니다. 여러 프로세스가 한 포트를 공유하지는 못하지만 한 프로세스가 한 포트로 여러 리모드와 연결되는 것은 Client/Server 구조의 일반적 형태입니다.

  3. 버퍼라고 하기는 그렇고...접속 대기 Queue가 있긴 합니다. 리슨 소켓은 연결에만 관여하며 실제 데이터 송/수신이 이루어지는 것은 아닙니다.

  4. 음...확인이 필요하겠습니다. 실험으로 가능하다는 것을 확인하셨다고 하니 그 말을 믿고 추측해보면 shutdown() 함수의 경우 입/출력 정지를 위해 사용합니다. 그런데 리슨 소켓은 3번에서 언급한 것처럼 실제 데이터 송/수신을 하지 않습니다. 따라서 의미가 없을 수도 있을 것 같습니다.

  5. 제 생각에 리슨 소켓을 닫아서 모든 클라이언트 소켓에 RST가 전달된 것이 아니라 리슨 소켓을 닫아버리면서 메인 스레드가 종료됐고 결과적으로 프로세스가 종료되어야 하기 때문에 프로세스가 개방한 소켓들을 OS가 강제로 닫은 것으로 보입니다. RST는 정상적이지 않은 세션 종료 발생 시 전달됩니다. 소켓이 비정상 종료되는 것은 바람직하지 않습니다. 정상적으로 closesocket() 할 수 있도록 구성해야 하겠습니다.

참고하시기 바랍니다.

손태정님의 프로필 이미지
손태정
질문자

추가 질문있습니다

 

  1. shutdown함수는 해당 소켓에 대한 recv, send같은 입출력 함수 호출을 제한하는 함수로 봐도 되는 건가요??

  2. 디버깅 모드로 한줄 한줄 실행했었는데 리스닝 소켓을 closesocket을 통해서 닫으니 wireshark 상으로 모든 클라이언트에게 RST 메시지가 날라갔었습니다.
    메인 쓰레드의 종료로 인한 것인지 잘 모르겠습니다 ㅠㅠ
    하지만 어떤 이유에서든지 RST 같이 비정상적인 소켓 종료는 좋지 않기 때문에 소켓을 하나하나 닫는 게 좋다는 말씀이신 거겠죠. 음... 그렇다면 혹시 소켓의 비정상 종료가 왜 안좋은지 알 수 있을까요??

 

항상 친절한 답변 감사합니다 :)

0

손태정님의 프로필 이미지
손태정
질문자

인터넷에 검색해보니 소켓의 identifier에는 src ip, src port, dst ip, dst port 4가지로 리스닝 소켓과 같은 포트번호를 가진다고 하는 글이 있던데 어느 것이 맞는 건가요??

 

그리고 리스닝 소켓에 shutdown함수를 호출했는데도 새로운 클라이언트 접속이 원활하게 이루어지던데 이건 루프백 주소를 사용해서 그럴까요??

널널한 개발자님의 프로필 이미지
널널한 개발자
지식공유자

2, 4번 질문으로 답변이 된 것 같습니다. 감사합니다.

0

안녕하세요, 인프런 AI 인턴이에요.

먼저, 쓰레드를 생성한 직후에 바로 CloseHandle 함수를 호출하여 쓰레드 핸들을 해제하는 것은 일반적으로 좋은 방법이 아닙니다. 쓰레드가 실행 중인 작업을 완료하기 전에 핸들을 해제하면, 쓰레드가 유효한 작업을 완료하지 못할 수 있으며, 예기치 않은 동작이 발생할 수 있습니다. 따라서 쓰레드의 동작이 완료될 때까지 안전하게 기다린 후에 핸들을 해제하는 것이 좋습니다.

소켓의 포트 번호에 대해서는, 여러 개의 소켓이 하나의 포트 번호를 공유할 수 있는 방법은 없습니다. 각 소켓은 고유한 포트 번호를 가져야 합니다. netstat와 wireshark에서 동일한 포트 번호가 나온다면, 이는 편의 기능으로 동작하고 있는 것이 아닌 소켓 간의 연결이 잘 이루어져 있기 때문입니다.

리스닝 소켓은 클라이언트의 접속 요청을 받는 소켓이므로, 일반적으로 데이터를 버퍼링하지 않습니다. 하지만 이는 운영체제나 라이브러리에 따라 다를 수 있으므로, 사용하는 환경에 따라 검토해야 합니다.

리스닝 소켓에 shutdown 함수를 호출했을 때의 효과는, 다른 클라이언트의 접속을 받지 못하도록 막는 것입니다. 이미 연결된 클라이언트와의 통신은 계속 유지될 수 있으며, 다른 클라이언트의 접속을 막기 위해서는 closesocket 함수를 사용해야 합니다.

마지막으로, 서버가 종료될 때 클라이언트 연결을 끊으려면, 모든 클라이언트 소켓을 순회하면서 closesocket 함수를 호출해주는 방식을 사용해야 합니다. 리스닝 소켓을 closesocket 함수로 해제하는 것은 클라이언트와의 통신을 끊는 것이 아니라, 서버에서 더 이상 클라이언트의 접속을 받지 않겠다는 의미이므로 주의해야 합니다.

더 자세한 내용이 필요하시다면, 해당 코드를 더 자세히 검토해보아야 할 것 같습니다.