ݺߣ

ݺߣShare a Scribd company logo
데이터 송수신 + 중급 소켓 프로그래밍
정수 인코딩
소켓은 바이트의 순서열을 전송.
데이터의 크기가 8bit를 넘을 경우 여러 바이트에 걸쳐 보내는데 이 때, 보내지는 순서가 리틀
-엔디안인지 빅-엔디안 인지판단하는 것이 중요함.
인터넷에서 사용되는 대부분의 프로토콜들은 빅-엔디안을 사용.
이를 네트워크 바이트 순서라 함.
하드웨어가 사용하는 기법은 리틀-엔디안이든 빅-엔디안이든 상관없이 네이티브 바이트 순
서 혹은 호스트 바이트 순서라고 함
ntohl, htons 같은 함수의 n또는 h는 변환시킬 데이터가 호스트냐 네트워크냐를 뜻 하고 to는
h, n은 변환될 데이터를 뜻함, s,l은 byte 수를 나타냄(short, long 등)
TCP 소켓을 스트림으로 포장하기
소켓을 스트림으로 포장하게 되면 fgets(), fpusts(), fread(), fwrite() 등을 사용 가능
FILE *fopen( int socketdes, const char *mode)
소켓을 스트림으로 포장하고 결과를 반환(error시 NULL)
int fclose(FILE *stream)
하부 소켓과 스트림을 닫는다.
int fflush(FILE *stream)
스트림에 버퍼링 된 데이터를 하부 소켓으로 밀어낸다.
구조체 오버레이
구조체로 데이터를 감싸서 구조체만 보낼 수 있다.
이 경우 구조체의 멤버 변수들을 각각 바이트 순서 변환한 후 구조체만 send할 수 있다.
구조체는 정렬(alignment)되는데 이때, 다음 두 가지 조건을 따른다.
구조체의 주소는 내부의 가장 큰 정수 자료형으로 나눠져야 한다. (가장 큰 자료형이 int값이
라면 4byte로 나눠져야 함)
자료형이 2바이트 이상일경우 그 필드의 크기로 정렬된다. 즉 int32의 경우 시작 주소가 4byte
로 나눠져야 한다. 2byte자료형이라면 시작주소가 2로 나눠저야 함
따라서 15바이트짜리 구조체를 만든다면 컴파일러가 알아서 pad를 넣어준다. 이 넣어주는
pad가 예측하기 어려우므로 구조체를 만들 때, padding을 고려하는 것이 좋다.
문자열과 텍스트
char와 wchar_t를 지원
문자열의 바이트 순서열간 변환을 하기 위해서는 wcstombs()를 사용한다. (wide character
string to multibyte string) 반대는 mbstowcs
size_t wcstombs(char * restrict s, const wchar_t * rstrict pwcs, size_t n);
** 여기서 restrict 키워드는 오직 그 포인터만 대상을 가리킬 수 있게 하는 것.
프레이밍 framing
TCP 방식으로 보내진 메세지는 경계가 없기 때문에 메세지의 끝을 찾기위해 두 가지 방법을
사용한다.
구분자 기반 방식 : 메세지의 끝을 특별한 기호로 나타낸다. ex) HTTP의 rnrn
길이 명시 방식 : 크기를 나타내는 길이 필드를 메세지 앞에 삽입한다.
시그널
signal은 어떤 이벤트가 발생했을 때 운영체제가 프로그램에 이를 알리는 기법
윈도우에서 메세지 같은것도 시그널의 한 종류인가?
시그널이 도착하여 블로킹 되지 않은 경우는 이를 처리한다.
시그널이 처리 중인데 다른 시그널이 도착하면 시그널은 중첩됐다고 한다. 나중에 도착한 시
그널은 그 종류에 따라 블록될 수도 있고 아닐 수도 있다.
시그널 처리중에 같은 종류의 또 시그널이 올 경우에는 보류시키고
이후에 또 같은 시그널이 온다면 버린다.
따라서 같은 시그널이 두 개 이상 도착해도 보류된 시그널 한 개만 수행된다.
넌블로킹 입/출력
소켓 호출의 기본동작은 블로킹이다. recv(), send() 등등 (recv()함수는 메세지를 받을때까지
블록 상태, send()는 전송할 데이터가 버퍼에 찰 때까지)
따라서 udp의 경우 데이터가 유실되면 무한히 블럭될 수 있다.
소켓에 사용되는 모든 호출을 넌블로킹으로 바꿀 수 있다.
fctrl이라는 함수는 몇 개 플래그, O_NONBLOCK 등으로 동작 수정이 가능하다.
비동기 입출력
논블로킹 소켓 호출의 문제점은 함수 호출이 성공할 때까지
주기적으로 호출(polling)해야한다는 것이다.
소켓호출의 성공이 예상될 때, 운영체제가 프로그램에 알려주면 좋을 것.
→ 소켓에 어떤 준비가 되었음을 통지하고 프로그램은 다른 일을 하는 기법을 비동기 입/출력
이라함
타임 아웃
타이머를 동작시켜 타임아웃시간이 지나면 응답을 포기하거나 재 전송하는 것.
unsigned int alarm(unsigned int secs)
멀티 태스킹
기존까지는 하나의 서버가 하나의 클라이언트에 대응했는데, 처리하는데 시간이 길어진다면
다른 클라이언트들은 계속 대기해야 하는 사태가 벌어진다.
멀티 태스킹서버는 클라이언트의 연결이 들어오면 그 연결을 처리하는 새로운 프로세스를 생
성한다. fork()하는 서버는 무한 루프를 돈다.
멀티 태스킹
for (;;) { // Run forever
// New connection creates a client socket
int clntSock = AcceptTCPConnection(servSock);
// Fork child process and report any errors
pid_t processID = fork();
if (processID < 0)
DieWithSystemMessage("fork() failed");
else if (processID == 0) { // If this is the child process
close(servSock); // Child closes parent socket
HandleTCPClient(clntSock);
exit(0); // Child process terminates
}
printf("with child process: %dn", processID);
close(clntSock); // Parent closes child socket descriptor
childProcCount++; // Increment number of child processes
멀티 태스킹
while (childProcCount) { // Clean up all zombies
processID = waitpid((pid_t) - 1, NULL, WNOHANG); // Non-
blocking wait
if (processID < 0) // waitpid() error?
DieWithSystemMessage("waitpid() failed");
else if (processID == 0) // No zombie to wait on
break;
else
childProcCount--; // Cleaned up after a child
}
다수의 수신자 처리
유니캐스트에서는 동일한 데이터를 보낼 때, 수신자의 숫자만큼 여러 번 전송해
야한다.
브로드 캐스트나 멀티 캐스트를 이용하여 다수의 수신자에게 동일한 데이터를 복
제하여 보낼 수 있다.
but UDP소켓만 가능하며, 브로드 캐스트는 LAN같은 지역범위에서만 가능함
전체 인터넷을 경유하는 멀티 캐스트는 불가능함.

More Related Content

중급 소켓프로그래밍

  • 1. 데이터 송수신 + 중급 소켓 프로그래밍
  • 2. 정수 인코딩 소켓은 바이트의 순서열을 전송. 데이터의 크기가 8bit를 넘을 경우 여러 바이트에 걸쳐 보내는데 이 때, 보내지는 순서가 리틀 -엔디안인지 빅-엔디안 인지판단하는 것이 중요함. 인터넷에서 사용되는 대부분의 프로토콜들은 빅-엔디안을 사용. 이를 네트워크 바이트 순서라 함. 하드웨어가 사용하는 기법은 리틀-엔디안이든 빅-엔디안이든 상관없이 네이티브 바이트 순 서 혹은 호스트 바이트 순서라고 함 ntohl, htons 같은 함수의 n또는 h는 변환시킬 데이터가 호스트냐 네트워크냐를 뜻 하고 to는 h, n은 변환될 데이터를 뜻함, s,l은 byte 수를 나타냄(short, long 등)
  • 3. TCP 소켓을 스트림으로 포장하기 소켓을 스트림으로 포장하게 되면 fgets(), fpusts(), fread(), fwrite() 등을 사용 가능 FILE *fopen( int socketdes, const char *mode) 소켓을 스트림으로 포장하고 결과를 반환(error시 NULL) int fclose(FILE *stream) 하부 소켓과 스트림을 닫는다. int fflush(FILE *stream) 스트림에 버퍼링 된 데이터를 하부 소켓으로 밀어낸다.
  • 4. 구조체 오버레이 구조체로 데이터를 감싸서 구조체만 보낼 수 있다. 이 경우 구조체의 멤버 변수들을 각각 바이트 순서 변환한 후 구조체만 send할 수 있다. 구조체는 정렬(alignment)되는데 이때, 다음 두 가지 조건을 따른다. 구조체의 주소는 내부의 가장 큰 정수 자료형으로 나눠져야 한다. (가장 큰 자료형이 int값이 라면 4byte로 나눠져야 함) 자료형이 2바이트 이상일경우 그 필드의 크기로 정렬된다. 즉 int32의 경우 시작 주소가 4byte 로 나눠져야 한다. 2byte자료형이라면 시작주소가 2로 나눠저야 함 따라서 15바이트짜리 구조체를 만든다면 컴파일러가 알아서 pad를 넣어준다. 이 넣어주는 pad가 예측하기 어려우므로 구조체를 만들 때, padding을 고려하는 것이 좋다.
  • 5. 문자열과 텍스트 char와 wchar_t를 지원 문자열의 바이트 순서열간 변환을 하기 위해서는 wcstombs()를 사용한다. (wide character string to multibyte string) 반대는 mbstowcs size_t wcstombs(char * restrict s, const wchar_t * rstrict pwcs, size_t n); ** 여기서 restrict 키워드는 오직 그 포인터만 대상을 가리킬 수 있게 하는 것.
  • 6. 프레이밍 framing TCP 방식으로 보내진 메세지는 경계가 없기 때문에 메세지의 끝을 찾기위해 두 가지 방법을 사용한다. 구분자 기반 방식 : 메세지의 끝을 특별한 기호로 나타낸다. ex) HTTP의 rnrn 길이 명시 방식 : 크기를 나타내는 길이 필드를 메세지 앞에 삽입한다.
  • 7. 시그널 signal은 어떤 이벤트가 발생했을 때 운영체제가 프로그램에 이를 알리는 기법 윈도우에서 메세지 같은것도 시그널의 한 종류인가? 시그널이 도착하여 블로킹 되지 않은 경우는 이를 처리한다. 시그널이 처리 중인데 다른 시그널이 도착하면 시그널은 중첩됐다고 한다. 나중에 도착한 시 그널은 그 종류에 따라 블록될 수도 있고 아닐 수도 있다. 시그널 처리중에 같은 종류의 또 시그널이 올 경우에는 보류시키고 이후에 또 같은 시그널이 온다면 버린다. 따라서 같은 시그널이 두 개 이상 도착해도 보류된 시그널 한 개만 수행된다.
  • 8. 넌블로킹 입/출력 소켓 호출의 기본동작은 블로킹이다. recv(), send() 등등 (recv()함수는 메세지를 받을때까지 블록 상태, send()는 전송할 데이터가 버퍼에 찰 때까지) 따라서 udp의 경우 데이터가 유실되면 무한히 블럭될 수 있다. 소켓에 사용되는 모든 호출을 넌블로킹으로 바꿀 수 있다. fctrl이라는 함수는 몇 개 플래그, O_NONBLOCK 등으로 동작 수정이 가능하다.
  • 9. 비동기 입출력 논블로킹 소켓 호출의 문제점은 함수 호출이 성공할 때까지 주기적으로 호출(polling)해야한다는 것이다. 소켓호출의 성공이 예상될 때, 운영체제가 프로그램에 알려주면 좋을 것. → 소켓에 어떤 준비가 되었음을 통지하고 프로그램은 다른 일을 하는 기법을 비동기 입/출력 이라함
  • 10. 타임 아웃 타이머를 동작시켜 타임아웃시간이 지나면 응답을 포기하거나 재 전송하는 것. unsigned int alarm(unsigned int secs)
  • 11. 멀티 태스킹 기존까지는 하나의 서버가 하나의 클라이언트에 대응했는데, 처리하는데 시간이 길어진다면 다른 클라이언트들은 계속 대기해야 하는 사태가 벌어진다. 멀티 태스킹서버는 클라이언트의 연결이 들어오면 그 연결을 처리하는 새로운 프로세스를 생 성한다. fork()하는 서버는 무한 루프를 돈다.
  • 12. 멀티 태스킹 for (;;) { // Run forever // New connection creates a client socket int clntSock = AcceptTCPConnection(servSock); // Fork child process and report any errors pid_t processID = fork(); if (processID < 0) DieWithSystemMessage("fork() failed"); else if (processID == 0) { // If this is the child process close(servSock); // Child closes parent socket HandleTCPClient(clntSock); exit(0); // Child process terminates } printf("with child process: %dn", processID); close(clntSock); // Parent closes child socket descriptor childProcCount++; // Increment number of child processes
  • 13. 멀티 태스킹 while (childProcCount) { // Clean up all zombies processID = waitpid((pid_t) - 1, NULL, WNOHANG); // Non- blocking wait if (processID < 0) // waitpid() error? DieWithSystemMessage("waitpid() failed"); else if (processID == 0) // No zombie to wait on break; else childProcCount--; // Cleaned up after a child }
  • 14. 다수의 수신자 처리 유니캐스트에서는 동일한 데이터를 보낼 때, 수신자의 숫자만큼 여러 번 전송해 야한다. 브로드 캐스트나 멀티 캐스트를 이용하여 다수의 수신자에게 동일한 데이터를 복 제하여 보낼 수 있다. but UDP소켓만 가능하며, 브로드 캐스트는 LAN같은 지역범위에서만 가능함 전체 인터넷을 경유하는 멀티 캐스트는 불가능함.