아래 코드는 스레드 생성 함수를 사용하여 만든 멀티스레드 TCP 서버의 기본 형태이다.
DWORD WINAPI ProcessClient(LPVOID arg)
{
// 전달된 소쳇 저장 - 3
SOCKET client_sock = (SOCKET) arg;
...
// 클라이너트 정보 얻기 - 4
int addrlen = sizeof(client_sock);
getpeername(client_sock, (SOCKADDR *) &clientaddr, &addrlen);
// 클라이언트와 데이터 통신 - 5
while (1)
{
...
}
...
}
int main(int argc, char **argv)
{
...
while (1)
{
// 클라이언트 접속 수용 - 1
client_sock = accept(listen_sock, ...);
...
// 스레드 생성 - 2
CreateThread(NULL, 0, ProcessClient, (LPVOID) client_sock, 0, NULL);
}
...
}
accept()
함수는 클라이언트와 통신할 수 있는 소켓을 리턴한다.getpeername()
함수를 호출해 클라이언트 IP 주소와 포트 번호를 얻는다. 이 코드는 필수는 아니며 클라이언트 정보 출력을 원할 때만 필요하다.스레드 함수에 소켓만 전달한 경우에는 별도의 주소 정보가 없으므로, 소켓을 통해 주소 정보를 얻는 기능이 필요하다.
getpeername()
함수는 소켓 데이터 구조체에 저장된 IP 주소와 원격 포트 번호를 리턴하고, getsockname()
함수는 지역 IP 주소와 지역 포트 번호를 리턴한다.
// 성공: 0, 실패: SOCKET_ERROR
int getpeername(
SOCKET s,
struct sockaddr *name,
int *namelen
);
// 성공: 0, 실패: SOCKET_ERROR
int getsockname(
SOCKET s,
struct sockaddr *name,
int *namelen
);
위 멀티스레드 TCP 서버의 기본 형태를 이용해 만든 멀티스레드 TCP 서버는 아래 링크와 같다.
https://github.com/LEEBONGHAK/TCP-IP_window_socket/blob/main/Chapter06/MultithreadTCPServer.cpp
실행 결과는 다음과 같다. 클라이언트가 2개 이상 접속해도 독립적으로 처리가 진행된다.
참고 자료
김성우 저, "TCP/IP 윈도우 소켓 프로그래밍", 한빛아카데미, 2018