티스토리 뷰

Programming/Network

Thread 란?

HwansChoi 2011. 3. 8. 19:15

13_network_스레드란.pdf

02_network_threadsample.zip

02_network_testeventsample.zip


스레드
  하나의 프로세스에서 다중 작업이 동시에 하는 것

스레드 관련 함수

--------------------------------------------------------
HANDLE WINAPI CreateThread(
  __in_opt   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in       SIZE_T dwStackSize,
  __in       LPTHREAD_START_ROUTINE lpStartAddress,
  __in_opt   LPVOID lpParameter,
  __in       DWORD dwCreationFlags,
  __out_opt  LPDWORD lpThreadId
);

 lpThreadAttributes - 스레드에 대한 보안 속성 구조체 포인터
 dwStackSize - 스레드에서 사용할 스택 사이즈, 0이면 시스템에서 사용하는 기본 사이즈를 제공한다.
 lpStartAddress - 스레드 구동 함수 포인터 typedef DWORD (WINAPI* LPTHREAD_START_ROUTINE)(LPVOID)
 lpParameter - 스레드 구동 함수에 넘길 파라메터
 dwCreateFlags - 값이 0이면 스레드가 만들어지자마자 구동되며, CREATE_SUSPENDED 값으로 지정되면, ResumeThread() 함수를 통해 스레드 구동을 할 수 있다.
 lpThreadId - 스레드 ID값

Return Value
 스레드 핸들
--------------------------------------------------------
DWORD WINAPI WaitForSingleObject(
  __in  HANDLE hHandle,
  __in  DWORD dwMilliseconds
);

 hHandle - 핸들
 dwMilliseconds - 타임아웃 대기시간, 밀리세컨 단위

Return Value
 WAIT_ABANDONED
 WAIT_OBJECT_0 - 핸들의 시그널 값 확인
 WAIT_TIMEOUT - 타임아웃
-------------------------------------------------------

[예제 코드 - 이벤트 확인]

#include <windows.h>
DWORD WINAPI TickThreadProc(LPVOID lpParam)
{
 HANDLE hEvent = (*(HANDLE*)lpParam);
 while(1)
 {
  Sleep(1000);
  SetEvent(hEvent);
  ResetEvent(hEvent);
 }
 return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
 HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

 DWORD dwThread_ID;
 HANDLE hThread = CreateThread(NULL, 0, TickThreadProc, (LPVOID)&hEvent, 0, &dwThread_ID);

 while(1)
 {
  if(WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0)
   printf("틱 떳다\n");
 }
}


[예제 코드 - 클라이언트]

#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX_BUFFER_SIZE 512

void err_quit(char* msg)
{
 LPVOID lpMsgBuf;
 FormatMessage(
  FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  NULL, WSAGetLastError(),
  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  (LPTSTR)&lpMsgBuf, 0, NULL);
 MessageBox(NULL, (LPCTSTR)lpMsgBuf, msg, MB_ICONERROR);
 LocalFree(lpMsgBuf);
 exit(-1);
}

void err_display(char* msg)
{
 LPVOID lpMsgBuf;
 FormatMessage(
  FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  NULL, WSAGetLastError(),
  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  (LPTSTR)&lpMsgBuf, 0, NULL);
 printf("[%s] %s", msg, (LPCTSTR)lpMsgBuf);
 LocalFree(lpMsgBuf);
}

DWORD WINAPI RecvThreadProc(LPVOID pParam)
{
 SOCKET sock = (*(SOCKET*)pParam);
 char recvBuffer[MAX_BUFFER_SIZE + 1];
 int readByte;

 while(1)
 {
  readByte = recv(sock, recvBuffer, MAX_BUFFER_SIZE, 0);
  if(readByte == SOCKET_ERROR)
  {
   err_display("recv()");
   break;
  }
  else if(readByte == 0)
  {
   break;
  }
  else
  {
   recvBuffer[readByte] = '\0';
   printf("서버 수신 데이터 :[%d Byte] %s\n", readByte, recvBuffer);
   recvBuffer[0] = '\0';
  }
 }

 return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
 WSADATA wsa;
 if(WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
  return -1;

 SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, 0);
 if(clientSocket == INVALID_SOCKET)
  err_quit("socket()");

 SOCKADDR_IN serverAddr;
 memset(&serverAddr, 0, sizeof(serverAddr));
 serverAddr.sin_family = AF_INET;
 serverAddr.sin_port = htons(5001);
 serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

 int retValue = connect(clientSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
 if(retValue == SOCKET_ERROR)
  err_quit("connect()");

 // 스레드 생성
 DWORD dwThread_ID;
 HANDLE hRecvThread = CreateThread(NULL, 0, RecvThreadProc, (LPVOID)&clientSocket, 0, &dwThread_ID);

 char writeBuffer[MAX_BUFFER_SIZE + 1];
 DWORD ret;

 while(1)
 {
  printf("서버에 보낼 데이터 : ");
  scanf_s("%s", &writeBuffer, MAX_BUFFER_SIZE);

  ret = WaitForSingleObject(hRecvThread, 100); // 스레드 상태 확인
  if(ret == WAIT_OBJECT_0) // 만약 스레드가 종료되었다면
  {
   printf("\n서버와의 접속이 끊어졌습니다.\n");
   break;
  }
  send(clientSocket, writeBuffer, strlen(writeBuffer), 0); // 입력한 데이터를 보낸다.
 }

 return 0;
}

[예제코드 - 서버]

#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX_BUFFER_SIZE 512

void err_quit(char* msg)
{
 LPVOID lpMsgBuf;
 FormatMessage(
  FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  NULL, WSAGetLastError(),
  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  (LPTSTR)&lpMsgBuf, 0, NULL);
 MessageBox(NULL, (LPCTSTR)lpMsgBuf, msg, MB_ICONERROR);
 LocalFree(lpMsgBuf);
 exit(-1);
}

void err_display(char* msg)
{
 LPVOID lpMsgBuf;
 FormatMessage(
  FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  NULL, WSAGetLastError(),
  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  (LPTSTR)&lpMsgBuf, 0, NULL);
 printf("[%s] %s", msg, (LPCTSTR)lpMsgBuf);
 LocalFree(lpMsgBuf);
}

DWORD WINAPI RecvThreadProc(LPVOID pParam)
{
 SOCKET sock = (*(SOCKET*)pParam);

 int retValue;
 char recvBuffer[MAX_BUFFER_SIZE + 1];

 while(1)
 {
  retValue = recv(sock, recvBuffer, MAX_BUFFER_SIZE, 0);
  if(retValue == SOCKET_ERROR)
  {
   err_display("recv()");
   break;
  }
  else if(retValue == 0)
  {
   break;
  }
  else
  {
   recvBuffer[retValue] = '\0';
   printf("%d %s\n", sock, recvBuffer);
   send(sock, recvBuffer, strlen(recvBuffer), 0);
  }
 }

 closesocket(sock);

 return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
 WSADATA wsa;
 if(WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
  return -1;

 SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, 0);
 if(listenSocket == INVALID_SOCKET)
  err_quit("socket()");

 SOCKADDR_IN serverAddr;
 memset(&serverAddr, 0, sizeof(serverAddr));
 serverAddr.sin_family = AF_INET;
 serverAddr.sin_port = htons(5001);
 serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
 
 int retValue = bind(listenSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
 if(retValue == SOCKET_ERROR)
  err_quit("bind()");

 retValue = listen(listenSocket, SOMAXCONN);
 if(retValue == SOCKET_ERROR)
  err_quit("listen()");

 SOCKET clientSocket;
 SOCKADDR_IN clientAddr;
 int nAddrLength;


 while(1)
 {
  nAddrLength = sizeof(clientAddr);
  clientSocket = accept(listenSocket, (SOCKADDR*)&clientAddr, &nAddrLength);
  if(clientSocket == INVALID_SOCKET)
  {
   err_display("accept()");
   continue;
  }

  printf("\n[TCP 서버] 클라이언트 접속 : 소켓번호 = %d, IP 주소 = %s, 포트번호 = %d\n",
   clientSocket, inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));

  DWORD dwThread_ID;
  HANDLE hClientThread = CreateThread(NULL, 0, RecvThreadProc, (LPVOID)&clientSocket, 0, &dwThread_ID);
 }

 closesocket(listenSocket);

 WSACleanup();

 return 0;
}

'Programming > Network' 카테고리의 다른 글

소켓의 입출력 모델 준비  (0) 2011.03.08
Socket Option (소켓 옵션 세팅)  (0) 2011.03.08
소켓이란? NetWork에 대한 첫걸음  (0) 2011.03.08
네트워크 란?  (0) 2011.03.08
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함