- 리눅스 vs. 윈도우
: 편견을 갖을 필요 없다. 각각의 장단점이 있다.
: 시스템콜 기반과 표준라이브러리 IO와 차이
: 시스템콜 메커니즘 자체는 리눅스와 윈도우가 같다.
: 리눅스는 무료 오픈소스로 파일 디스크립터, 오픈파일 등의 세팅을 바꾸어줄수 있지만 윈도우즈는 변경하기가 힘들고, 가격이 비싸지만 (windows server 같은 경우 cpu당 라이센스 비용 지불), 개발이 쉽다.
: 바로 함수를 호출하는 메커니즘 vs 하나를 거쳐 호출하는 메커니즘
: mono vs micro
: 커널을 다시 빌드해야함 vs 모듈처럼 사용 가능하지만 성능 저하
: android 코드를 분석해보면 bionic -> 각각의 CPU에 대해 존재하는 이유는 시스템콜 때문이다. 시스템 콜
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h > // stdin, stdout, stderr : FILE* // STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO : int // task_struct // 1. socket programming 저수준 IO를 사용합니다. // 2. 저수준 IO : 운영체제에서 제공하는 IO 관련 API // Windows : Win32/64 API // Linux : System Call // 3. 프로세스를 통해 파일을 관리한다. // ulimit -a int main() { // FILE* fp = fopen("sample", "r"); int fd = open("sample", O_RDONLY); printf("fd : %d\n", STDIN_FILENO); printf("fd : %d\n", STDOUT_FILENO); printf("fd : %d\n", STDERR_FILENO); printf("fd : %d\n", fd); // fd 출력시 3인 이유는 표준 입출력, 에러에 대한 fd가 열려있기 때문이다 // VFS라고 부른다 -> 다형성 // 내부적으로 파일, 디바이스를 다루는 모든 방식은 파일로 되어있다. 이를 사용하기 위해서는 각각을 모두 열어야한다. -> 동적바인딩을 통해서 // 리눅스는 array로 파일디스크립터 관리, 윈도우즈는 파일디스크립터 핸들 }
∴버퍼링 정책 3가지
1. Full Buffering : Buffer가 가득 차면 화면에 출력 → File I/O
2. Line Buffering : ‘\n’이 오면 화면에 출력 → printf의 경우에 해당
3. Non Bufering : 버퍼링을 하지 않음. → fprintf(stderr,””);에 해당pirntf("error");
while(1);
//출력하지 않는다.
pirntf("error\n");
while(1);
//출력한다.
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> int main() { int fd = open("sample", O_RDONLY); printf("fd : %d\n", fd); // 문제점 // 1. 에러 발생시 -1 리턴 // 2. 버퍼의 크기가 너무 작을 경우, 빈번한 컨텍스트 스위칭으로 인한 // 성능 저하가 있다. #if 0 char ch; while (read(fd, &ch, sizeof ch) > 0) putchar(ch); #endif // 3. read(fd, buf, size) // size : 버퍼의 최대 크기 // 4. write(fd, buf, size) // size : 쓰고자 하는 데이터의 실제 양 char buf[128]; int ret; while ((ret = read(fd, buf, sizeof buf)) > 0) { write(1, buf, ret); // buf[ret] = '\0'; // printf("%s", buf); } close(fd); // close를 안해도 문제가 없었던 이유 // 프로세스가 종료되면서 소유하고 있던 자원을 모두 해지 // app영역에서는 프로세스 종료로 OS가 메모리를 수거함. 대부분 커널의 누수 // 정적분석은 new와 delete쌍을 찾아서 싱글톤은 메모리 누수로 인식함 // 동적분석은 비쌈 }
클라이언트 작성하기
- http 통신#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <errno.h> #include <string.h> int main() { // 1. 소켓 생성 : socket() int sd = socket(PF_INET, // 프로토콜 SOCK_STREAM, // TCP(SOCK_STREAM), UDP(SOCK_DGRAM) IPPROTO_TCP); // 하위 프로토콜(생략, 0 으로 지정 가능) // 2. 서버 주소 지정 : 초기화 이전에 0으로 초기화해야 한다. // 문자열 ip -> 32 bit : inet_addr struct sockaddr_in addr = {0, }; addr.sin_family = AF_INET; addr.sin_port = htons(80); addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 3. 접속 수행 int ret = connect(sd, (struct sockaddr*)&addr, sizeof(addr)); if (ret == -1) { // 에러 처리 방법 3가지 // 1. printf("connect() error : %d\n", errno); // 2. char* msg = strerror(errno); // printf("connect() error : %s\n", msg); // 3. perror("connect()"); goto err; } { printf("Connection succeed!!\n"); // "GET \n\n" char buf[1024] = "GET /\n\n"; write(sd, buf, strlen(buf)); int len; while ((len = read(sd, buf, sizeof(buf))) > 0) { write(1, buf, len); } } err: // 4. 접속 종료 close(sd); }
- DNS#include <stdio.h> // domain -> ip address // : gethostbyname // gethostbyname #include <netdb.h> // inet_ntoa: 네트워크로부터 온 패킷을 아스키코드로 바꾸어 주는 것 #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main() { struct hostent* host = gethostbyname("www.google.com"); // name printf("host name : %s\n", host->h_name); // alias for (int i = 0 ; host->h_aliases[i] ; i++) { printf("Alias[%d] : %s\n", i + 1, host->h_aliases[i]); } for (int i = 0 ; host->h_addr_list[i] ; i++) { printf("Address[%d] : %s\n", i+1, inet_ntoa(*(struct in_addr*)host->h_addr_list[i]) ); } }
'Programing > Server Model' 카테고리의 다른 글
서버 모델 - I/O 모델 개요 (0) | 2016.02.22 |
---|---|
서버 모델 - 리눅스 소켓 프로그래밍(3) (0) | 2016.02.22 |
서버 모델 - 리눅스 소켓 프로그래밍(2) (0) | 2016.02.18 |
서버 모델 - 리눅스 소켓 프로그래밍(1) (0) | 2016.02.18 |
서버 모델 - 기초 (0) | 2016.02.16 |