이 글은 윤성우의 TCP/IP 소켓 프로그래밍 책을 참고하였습니다.
순서
I. 멀티 스레드 흐름 간단 정리
II. 스레드의 소멸
III. 멀티 스레드 서버 구현
I. 멀티 스레드 흐름 간단 정리
1. 스레드는 멀티 프로세스와 다르게 한 프로세스 안에서 실행 흐름만 독립적, 힙과 데이터 영역은 공유했다.
2. pthread_create()로 스레드를 생성했다. 하지만 프로세스 반환 시, 스레드의 실행 끝을 기다려주지 않음!
3. pthread_join()으로 프로세스를 Block 걸어 스레드를 끝내고 프로세스를 반환했었다.
4. 하지만 공유하는 힙 및 데이터 주소에 동시 접근 문제 발생!!! (동기화 필요)
--> 접근 시 자물쇠 역할을 하는 뮤텍스와, 세마포어를 사용했었다.
5. 뮤텍스 또는 세마포어를 정의해주고 공유 영역(임계 영역) 시작과 끝에
pthread_mutex_lock(), pthread_mutex_unlock()
semaphore_wait(), semaphore_post()
사용해 다른 스레드의 주소 진입을 설정해주었다.
II. 스레드의 소멸
우리는 3번 단계의 pthread_join()을 이용해서 스레드를 기다려주었다.
하지만 이 함수의 문제점은
1. 스레드 종료 시까지 Blocking상태로 남아있게 된다.
2. 멀티 스레드일 때 해당 스레드 이외의 다른 스레드의 자원은 할당 중이다.
이를 해결하기 위한 함수는 다음과 같다.
#include <pthread.h>
int pthread_detach(pthread_t thread);
--> 성공 시 0, 실패 시 0 이외의 값 반환
ㄴ. thread : 종료와 동시에 소멸시킬 쓰레드의 ID정보 전달
이 함수는 각 스레드에 선언되어, 스레드가 종료되면 그 즉시 자원을 반환한다.
동시에, 종료되지 않은 스레드가 종료되거나, Blocking에 걸리지도 않는다.
따라서 위의 함수로 스레드의 소멸을 유도하는 것이 좋다.
주의!! 해당 스레드를 대상으로 pthread_join 함수의 호출이 불가능하다.
III. 멀티 스레드 서버 구현
본 소스코드는 thread와 mutex를 사용한다.
기본 통신 구현 함수들을 일부 생략함.
<hide/>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#define BUF_SIZE 100;
#define MAX_CLNT 256;
void* handle_clnt(void* arg);
void send_msg(char* msg, int len);
void error(char* msg); // 디버깅용 코드는 생략, 주석으로 반환값만 알려줌.
// 임계영역임!
int clnt_cnt =0; // 현재 클라이언트 수
int clnt_socks[MAX_CLNT]; // 클라이언트 fd를 담은 배열
pthread_mutex_t mutx;
int main()
{
int serv_sock, clnt_sock;
struct sockaddr_in serv_adr, clnt_adr;
int clnt_addr_size;
pthread_t t_id;
pthread_mutex_init(&mutx,NULL); // 뮤텍스 설정
1. socket()
2. serv_adr 구조체에 변수 입력
3. bind()
4. listen()
while(1)
{
clnt_addr_size = sizeof(clnt_adr);
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_addr_size);
// 뮤텍스 열고 현재 접속된 클라이언트 배열에 추가해줌
pthread_mutex_lock(&mutx);
clnt_socks[clnt_cnt++] = clnt_sock;
pthread_mutex_unlock(&mutx);
// 스레드 생성해줘서 클라이언트 계속 돌려줌
pthread_create(&t_id, NULL, handle_clnt, (void*)&clnt_sock);
// 방금 생성한 스레드의 detach로 소멸유도
pthread_detach(t_id);
printf("Connected Client IP: %s \n",inet_ntoa(clnt_adr.sin_addr));
}
close(serv_sock);
return 0;
}
// 메인 스레드
void* handle_clnt(void* arg)
{
int clnt_sock= *(int*)arg;
int str_len =0;
char msg[BUF_SIZE];
// 메시지가 계속 들어오면 while문 돌고 길이가 0이면 탈출해 소켓닫음
while((str_len = read(clnt_sock, msg, sizeof(msg))) !=0)
{
send_msg(msg, str_len);
}
// 주소 접근할것임
pthread_mutex_lock(&mutx);
// 현재 클라이언트 닫고 하나씩 앞으로 당겨옴
for(int i=0; i<clnt_cnt;i++)
{
if(clnt_sock == clnt_socks[i])
{
while(i++<clnt_cnt-1)
{
clnt_socks[i] = clnt_socks[i+1];
}
break;
}
}
clnt_cnt--; //개수 줄이고
pthread_mutex_unlock(&mutx); // 접근 끝났으니 문열어줌
close(clnt_sock); //소켓 닫기
return NULL;
}
// 모든 클라이언트에게 다 write함
void send_msg(char* msg, int len)
{
pthread_mutex_lock(&mutx);
for(int i=0;i<clnt_cnt;i++)
write(clnt_sock[i],msg,len);
pthread_mutex_unlock(&mutx);
}
'Programming > Network(C++)' 카테고리의 다른 글
[Network][Thread] 멀티스레드(6)_윈도우 스레드 구현(Window) (0) | 2020.12.23 |
---|---|
[Network][Thread] 멀티스레드(4)_스레드 동기화(Mutex, Semaphore)(Linux) (0) | 2020.12.21 |
[Network][Thread] 멀티스레드(3)_동시접근의 문제점 (0) | 2020.12.21 |
[Network][Thread] 멀티스레드(2)_스레드의 생성 및 실행(pthread)(Linux) (0) | 2020.12.20 |