TCPClient.c |
#include "smart.h" |
TCPserver.c |
#include "smart.h" #define MAXPENDING 5 #define MAXUSER 10 ///// Thread ID 를 알기위해서 구조체로 넘겨줌. // typedef struct _TInfo { unsigned int uiUser; int iSock; }TInfo; ///// void *ClientRecv(void *); ///// 크리티컬 섹션 시작. ///// unsigned int uiUser; pthread_t t_ID[MAXUSER]; // 쓰레드를 여러개 사용하므로 배열로 잡음. ///// 크리티컬 섹션 종료. ///// ///// 뮤텍스 객체 선언. ///// pthread_mutex_t MLock; int main(int iArg, char *cpArg[]) { int servSock; TInfo st_TempInfo; struct sockaddr_in echoServAddr; struct sockaddr_in echoClntAddr; unsigned short echoServPort; unsigned int clntLen; int iRet; int iCnt; int iCnt2; unsigned char ucBuff[500]; if(1 == iArg) { echoServPort = 9999; } else if(2 == iArg) { echoServPort = atoi(cpArg[1]); } servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(0 > servSock) { printf("socket() failed"); return 0; } memset(&echoServAddr, 0, sizeof(echoServAddr)); echoServAddr.sin_family = AF_INET; echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); echoServAddr.sin_port = htons(echoServPort); iRet = bind(servSock, (struct sockaddr *)&echoServAddr, sizeof(echoServAddr)); if(0 > iRet) { close(servSock); printf("bind() failed"); return 0; } iRet = listen(servSock, MAXPENDING); if(0 > iRet) { close(servSock); printf("listen() failed"); return 0; } clntLen = sizeof(echoClntAddr); uiUser = 0; // 뮤텍스 초기화. pthread_mutex_init(&MLock, NULL); while(1) { st_TempInfo.iSock = accept(servSock, (struct sockaddr *)&echoClntAddr, &clntLen); if(0 > st_TempInfo.iSock) { printf("accept() failed"); continue; } printf("Handling client ip : %s\n", inet_ntoa(echoClntAddr.sin_addr)); printf("Handling client port : %d\n", ntohs(echoClntAddr.sin_port)); printf("Handling client socket number : %d\n", st_TempInfo.iSock); if(MAXUSER <= uiUser) { close(st_TempInfo.iSock); continue; } // Lock ! // uiUser 접근할때마다 Lock/UnLock 을 걸어줘서. // 다른 Thread가 접근을 못하도록 한다. 즉 공유자원을 // 같이 써서 발생하는 혼선을 막는다. pthread_mutex_lock(&MLock); // 구조체에다가 uiUser 의 값을 넣어둠. st_TempInfo.uiUser = uiUser; // pthread_create 의 마지막 인자를 구조체 통째로 넘겨줌. pthread_create(&t_ID[uiUser], 0, ClientRecv, &st_TempInfo); ++uiUser; pthread_mutex_unlock(&MLock); // Unlock ! while(0 != st_TempInfo.iSock); // ClientRecv 동작 하는지 확인. printf("현재 접속자 수 : %d\n", uiUser); } close(servSock); return 0; } // Thread ID 를 받아서 Client Sock을 확보 void *ClientRecv(void *vp) { unsigned char uc_Buffer[500]; int iRet; // 구조체에 있는 값을 받아서 iSock에다가 Thread ID // uiUser 에다가 유저 숫자 대입. int iSock = ((TInfo *)vp)->iSock; unsigned int ui_MyUser = ((TInfo *)vp)->uiUser; // 구조체안의 iSock 의 번호를 삭제. ((TInfo *)vp)->iSock = 0; // 구조체 안의 iSock 번호가 0 이므로 112줄의 while문을 통과. // Thread 중복을 방지하기 위해서 사용. // Thread 와 Main 이 여기서 부터 따로 돌겠다. while(1) { iRet = read(iSock, uc_Buffer, 500); if(1 >= iRet) { // Ctrl+C로 오류가 뜨면 멈춤. break; } uc_Buffer[iRet - 1] = 0; printf("[%dSock]:[%s]\n", iSock, uc_Buffer); if('$' == uc_Buffer[0]) { break; } } // uiUser 나감. pthread_mutex_lock(&MLock); --uiUser; t_ID[ui_MyUser] = t_ID[uiUser]; pthread_mutex_unlock(&MLock); close(iSock); return 0; } |
<출력 화면>
뮤텍스 출처 :
출처 : http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/Thread/Beginning/PthreadApiReference
- 프로세스 간 메시지를 전송하거나, 혹은 공유메모리를 통해서 특정 data를 공유하게 될 경우 발생하는 문제는, 공유된 자원에 여러 개의 프로세스가동시에 접근 하면서 발생한다. 단지, 한번에 하나의 프로세스만 접근 가능하도록 만들어 줘야 하고, 이때 Semaphore를 쓴다.
- Thread 에서는 뮤텍스, 프로세스에서는 세마포어
- 교착상태를 방지하기 위해, A 프로세스가 접근했을 때 다른 프로세스의 접근을 막고, 끝난 후 접근을 풀어준다. 이때 세마포어로 접근을 막고 접근을허용할 수 있다.
- 차단을 원하는 자원에 대해서 semaphore를 생성하면 해당 자원을 가리키는 semaphore 값이 할당된다.
- 이 값이 0 이면 해당 자원에 접근할 수 없고, 0보다 크면 해당 자원에 접근할 수 있다.
- 그러므로, 자원에 접근하기 전에 semaphore 값을 검사해서 값이 0 이면 자원을 사용할 수 있을 때까지 기다리고, 0 보다 크면 자원에 접근해서semaphore 값을 0으로 감소 시켜서, 다른 프로세스가 자원에 접근할 수 없도록 하고, 자원의 사용이 끝나면 다시semaphore 값을 증가 시켜 다른프로세스가 사용할 수 있게 해준다.
- 뮤텍스(Mutex) – 상호 배제
- 화장실에 들어가기 위한 열쇠를 한 사람이 가지고 있다면, 그 사람만이 들어갈 수 있다. 대기열(큐)에 기다리게 됨. à 세마포어의 일종이다.
- Critical Section을 가진 Thread 들이 running time이 서로 겹치지 않게, 각각 단독으로 실행하게 하는 기술
- 뮤텍스는 한 번에 하나의 Thread만이 실행되도록 하는 재 입장할 수 있는 코드 섹션 직렬화된 접근이 가능하게 할 때 사용
- 뮤텍스 객체는 제어되는 섹션에 하나의 Thread만을 허용하기 때문에 해당 섹션에 접근하려는 다른 Thread들을 강제적으로 막음으로써 첫 번째 Thread가 해당 세션을 빠져 나올 때까지 기다린다.
- 세마포어(Semaphore)
- 화장실이 n칸(접근할 수 있는 최대 허용치 만큼 동시에 사용자 접근을 할 수 있게 함), 세마포어 카운트가 0이면 대기
- Dead Lock을 피하기 위한 기술 중 하나
- Thread가 Critical Section에 접근할 때, 해당 Thread는 Semaphore 카운트를 감소시키고, 수행 종료 후 원래대로 증가.
- 공유 리소스에 접근할 수 있는 최대 허용치 만큼 동시에 사용자 접근을 할 수 있게 하는 기술
- 동기화 대상이 여러 개일 경우에 사용
- 세마포어는 내부에 카운트를 두어서 소유권을 가질 수 있는 쓰레드 들의 수를 설정할 수 있다.
- 동시에 실행될 수 있는 쓰레드를 설정 할 수 있다는 뜻.
- 바이너리 세마포어가 아닌 경우는 세마포어(내부 카운트 2이상)는 스레드가 동시에 같은 공유 자원에 접근할 수 있기 때문에 Critical Section이나 뮤텍스 같은 다른 동기화 자원과 함께 사용해야한다.
- 동시에 접근 할 수 있는 쓰레드의 수를 설정하기 위해 쓰레드 풀링을 사용한다.
'TCPIP' 카테고리의 다른 글
2013.07.12_SockCapture_소켓으로 패킷캡쳐하기_ (0) | 2013.07.12 |
---|---|
2013.07.10_Thread를 이용한 Server 구현. (0) | 2013.07.10 |
2013.07.08_Inter Process Communication(IPC)_활용. (0) | 2013.07.09 |
2013.07.04_멀티태스킹 테스트 (0) | 2013.07.05 |
2013.07.03_UDP_기타이론설명By종영이형 (0) | 2013.07.04 |