반응형


참조    : http://ssambback.tistory.com/entry/Unix-or-Linux-%EB%B3%84-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EC%97%90%EB%9F%AC%EB%93%A4


프로그램 에러 시그널들 (SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGABRT) - 매우 중요 ★★★★★

다음의 시그널들은 심각한 프로그램의 에러가 운영체제나 컴퓨터 자체에 의해 검출되었을 때 발생 된다. 
일반적으로, 이들 시그널 모두는 당신의 프로그램이 심각하게 깨져있고, 에러가 포함된 그 실행을 계속할 아무런 방법이 없음을 지적한다.


어 떤 프로그램들은 프로그램의 에러 시그널로 인해서 종료되기전에 그들을 깨끗하게 처리한다. 예를 들어, 터미널 입력의 반향을 끈(tnun off) 프로그램들은 다시 반향을 켤 목적으로 프로그램 에러 시그널들을 처리할 것이다. 핸들러는 시그널을 위한 디폴트 동작을 정하고 그 동작을 함으로써 끝날 것이다. 만일 프로그램이 시그널 핸들러를 가지지 않았다면, 프로그램은 그 시그널로 인해서 종료될 것이다.

SIGFPE 시그널은 심각한 산술적 에러를 보고한다. 그 이름이 "floating-point exception"에서 유래된것이라 할지라도, 이 시그널은 실제로는 모든 산술적 에러들에 작용한다. 만일 어떤 프로그램이 어떤 위치에 정수 데이터를 저장하고 그 데이터에 플로팅-포인트 명령을 사용한다면, 이것은 그 프로세서가 데이터를 플로팅-포인트 수로써 인식할 수 없기 때문에 종종 "유용하지 않은 연산"의 원인이 된다.

SIGILL 시그널의 이름은 "비합법적인 명령(illegal instruction)"에서 유래되었다
그것은 쓸모없거나 특권이 부여된 명령어를 실행하려 했다는 의미이다. 
오직 유용한 명령어만이 발생된 C 컴파일러에서, SIGILL은 전형적으로 실행 가능 파일이 훼손되었거나, 당신이 데이터를 실행하려 시도했다는 것을 지적한다. 

후자의 상황이 발생되는 일반적 상황으로는 함수를 위한 포인터가 있을 것이라고 예상된 곳에서 유용하지 않은 오브젝트를 파싱하거나, 자동 배열의 끝을 넘어서 기록을 하고( 또는 자동 변수를 위한 포인터와 유사한 문제들) 스택 프레임의 반환 어드레스 처럼 스택에서 
다른 데이터의 훼손과 같은 문제들이 있다.

SIGSEGV 시그널은 할당된 메모리의 범위를 벗어나는곳에서 읽거나, 쓰기를 시도할 때 발생 된다. 
(실제로, 그 시그널들은 프로그램이 충분한 영역을 할당받지 못할 때 시스템 메모리 보호 메커니즘에 의해서 발생한다.) 

그 이름은 "segmentation violation"의 약자이다. 
SIGSEGV 상황이 발생되는 가장 일반적인 방법은 비참조 되는 널( defeferencing a null) 이나 초기화되지 않은 포인터에 의한 것이다. 

널 포인터는 주소 0으로 참조되고, 대부분의 운영체제는 이 주소가 정확하게 유용하지 않음을 확실히 
하기 때문에 
비참조 널 포인터는 SIGSEGV가 발생될 것이다. 
(어떤 운영체제는 주소가 0인 메모리도 유용하고, 비참조 널 포인터는 그들 시스템상에서는 시그널을 발생하지 않는다.) 
비초기화된 포인터에서는, 유용하지 않거나, 유용하더라도 임의의 주소들을 갖게된다. 
SIGSEGV 상황이 얻어지는 다른 일반적 방법은 배열에 포인터를 사용했을 때 그 배열의 끝을 체크하기를 실패했을 때이다. 

SIGBUS 시그널은 유용하지 않은 포인터가 비참조되었을 때 발생 된다. 
SIGSEGV 처럼, 이 시그널은 초기화되지 않은 포인터를 비참조 한 것의 결과이다. 
두 시그널의 차이점은 SIGSEGV는 유용한 메모리에서 유용하지못한 억세스를 지적하고, 
SIGBUS는 유용하지못한 주소를 억세스 하는 것을 지적한다. 
특별하게, SIGBUS 시그널은 4개로 나누어지지 않은 주소에 4-단어 정수로 참조하는것처럼, 
부적당한 포인터가 비참조 됨으로써 발생한다. 
(각종 시스템은 주소 정렬은 위한 자신만의 필요조건을 갖는다.) 이 시그널의 이름은 "bus error"의 약자이다.

SIGABRT 시그널은 프로그램 그 자체와 abort가 호출되었음을 보고함으로써 발생되는 에러를 지적한다.

2. 종료 시그널 (SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGKILL) - 중요 ★★★★

이들 시그널들은 이런 저런 방법으로 프로세스를 종료함을 알리기위해 사용된다. 
그들은 완전히 다른 목적을 위해 사용되기 때문에 다른 이름을 가졌고, 프로그램은 그들은 다르게 취급하기를 원할 것이다.
이들 시그널들은 처리하기 위한 이유는 보통 당신의 프로그램이 실제로 종료되기전에 적당하게 처리할 수 있도록 하기 위한 것이다. 
예를 들어, 당신은 상황정보를 저장하고, 임시 파일들을 지우고, 이전의 터미널 모드를 반환하기를 원할수도 있다. 
그와 같이 핸들러(handler)는 발생된 시그널을 위한 디폴트 동작을 지정하고 그리고 그 시그널을 다시 발생시킴으로써 종료할 것이다. 
이것은 만일 프로그램이 핸들러를 가지지 않았더라도, 그 시그널로 인해서 프로그램이 종료될 것이다.

SIGHUP ("hang-up") 시그널은 사용자 터미널의 단절을 보고하기 위해 사용되어지는데, 
아마도 네트웍이나 전화선 연결이 끊어졌기 때문이다. 

SIGINT("program interrupt") 시그널은 사용자가 INTR 문자를 (보통 C-c)을 입력했을 때 보내어진다. 

SIGQUIT 시 그널은 다른 키_QUIT 문자, 보통 C-\_에 의해서 제어된다는 것을 제외하고는 SIGINT와 유사하고, 그 프로세스가 종료 될 때 프로그램 에러 시그널처럼 코어 파일을 작성한다. 당신은 사용자에 의해 "검출된" 프로그램 에러 상황으로 이들을 생각할 수 있다. 

SIGTERM 시그널은 프로그램을 종료하는데 사용하는 포괄적인 시그널이다. SIGKILL과 달리, 이 신호는 블록되어진고, 처리되어지고 무시되어질 수 있다.

SIGKILL 시그널은 즉각적인 프로그램 종료를 일으키기 위해서 사용되어진다. 이 시그널은 처리되거나, 무시되거나 할 수 없고, 그 결과는 항상 치명적이 된다. 이 시그널은 블록하는것도 불가능하다. 

3. 알람 시그널 (SIGALRM, SIGVTALRM, SIGPROF) - 알아도 그만.. 몰라도 그만..  ^^;;

그들 시그널은 타이머의 경과를 지적하는데 사용되어진다. 
그들 시그널을 위한 디폴트 동작은 프로그램을 종료를 일으키는 것이다. 
이 디폴트 동작은 거의 유용하지 않다. 
그 들 시그널을 사용하는 대부분의 방법은 어느 경우에 맞는 핸들러 함수들을 요구하는 것이다.

SIGALRM 시그널은 전형적으로 실제또는 클럭 시간을 계산한 타이머의 경과를 지적한다. 
예를 들어 alarm 함수에의해 사용되어진다. 

SIGVTALRM 시그널은 전형적으로 현재 프로세스에 의해 사용된 CPU시간을 계산하는 타이머의 경과를 지적한다. 
그 이름은 "virtual time alarm"의 약자이다.

SIGPROF 시그널은 현재의 프로세스에 의해 사용된 CPU 시간과, 
프로세스를 대신하여 시스템에의해 사용된 CPU시간의 둘을 계산한 타이머의 경과를 지적하는데 사용된다. 
타이머가 자원의 프로파일링을 위한 도구로써 사용되어지므로, 시그널의 이름이 SIGPROF이다.

4. 비동기 입/출력 시그널 (SIGIO, SIGURG)

이 절에 설명된 시그널들은 비동기 입/출력 도구들과 함께 사용되어진다. 
당신은 어떤 특정한 파일 기술자가 그들 시그널을 발생시키도록 하기 위해서 fcntl을 호출함으로써 명백한 동작을 취하도록 해야한다.

SIGIO 시그널은 파일기술자가 입력 또는 출력을 수행할 준비가 되어있을 때 보내어진다. 
대부분의 운영체제에서, 터미널과 소켓만이 SIGIO를 발생시킬 수 있다. 
보통의 파일들을 포함한 다른 종류들은 당신이 그들에게 요청했을지라도 SIGIO신호를 발생시키지 않는다.

SIGURG 시그널은 소켓에 도착한 데이터가 "긴급"하거나 범위를 벗어 났을 때 보내어진다.

5. 작업 제어 시그널 (SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU) - 중요 ★★★★

이들 시그널은 작업 제어를 지원하기 위해서 사용되어진다. 
만일 당신의 시스템이 작업 제어를 지원하지 않는다면 시그널들은 발생되어지거나, 처리될 수는 없지만 매크로들은 정의되어있다. 
당신이 실제로 작업이 어떻게 제어되는지를 이해할 수 없다면 그들 시그널을 그대로 방치할 것이다.

SIGCHLD 시그널은 자식 프로세스들중의 하나라도 종료되거나 멈출 때마다 부모 프로세스에게 보내어진다. 
이 시그널을 위한 디폴트 동작은 그것을 무시하는 것이다. 

당신은 프로세스가 계속되도록 하기 위해서 SIGCONT 신호를 보낼 것이다.
SIGCONT 시그널을 위한 디폴트 동작은 만일 그 프로세스가 멈추었다면 그 프로세스를 계속하도록 만드는 것이고 
그렇지 않다면 그것을 무시하는 것이다. 
대부분의 프로그램에서는 SIGCONT를 처리할 아무런 이유가 없다. 
그들은 전에 멈추었었음을 인식함이 없이 계속 실행되고 있다고 가정한다. 

SIGSTOP 시그널은 프로세스를 멈춘다. 그것은 처리되거나, 무시되거나 블록될 수 없다.

SIGTSTP 시그널은 상호 작용하는 멈춤 신호이다. SIGSTOP와는 달리 이 신호는 처리되거나 무시되어질 수 있다. 
당신의 프로그램에서 프로세스가 멈추었을 때 파일이나 시스템 테이블을 안전한 상황으로 만들어놓을 특별한 필요가 있다면 
이 신호를 처리할 수 있다.

한 프로세스가 배경 작업으로써 실행되고 있는 동안 사용자의 터미널로부터 읽을 수 없다. 
배경 작업에 속한 어느 프로세스가 터미널로부터 읽으려 시도할 때, 그 작업에 속한 모든 프로세스는 SIGTTIN 신호를 받는다. 
이 시그널을 위한 디폴트 동작은 그 프로세스를 멈추는 것이다. 

SIGTTOU 시그널은 배경 작업에 속한 프로세스가 터미널에 출력하려 시도하거나 그 터미널 모드를 설정하려 시도할 때 발생 된다. 
다시 말하면 디폴트 동작은 그 프로세스를 멈추는 것이다. 
프로세스가 멈추어있을 동안, SIGKILL 시그널과 SIGCONT시그널을 제외하고는 어느 다른 시그널들은 배달되어질 수 없다.

SIGKILL 시그널은 항상 프로세스의 종료를 유발하고 블록되거나 무시될 수 없다. 
당신이 SIGCONT 시그널을 무시하거나 블록할 수 있지만, 그것은 만일 그 프로세스가 멈추어져있다면 프로세스가 계속되도록 한다. 
프로세스에게 보낸 SIGCONT 시그널은 아직 미해결인채로 남아있는 멈춤 시그널을 프로세스가 버리도록 한다. 
이와 비슷하게, 어떤 프로세스에서 아직 미해결인채로 남아있는 SIGCONT 시그널은 멈춤 시그널이 도착했을 때 버려진다. 
고아가 되어버린 프로세스 그룹에 있는 한 프로세스에게 SIGTSTP, SIGTTIN, 또는 SIGTTOU 시그널을 보내면 그것은 처리되지도 않고, 
그 프로세스는 멈추어 지지도 않는다. 
그것을 계속할 아무런 방법이 없는 부당하게 되어버린 프로세스를 멈추게 하라. 
운영체제에 의존하지 말고당신이 무언가를 사용해서 멈추게 하라. 어떤 시스템은 아무런 일도 하지 않을 것이다. 
다른 시스템들은 대신에 SIGKILL 또는 SIGHUP와 같은 시그널들을 배달할 것이다. 

6. 잡다한 시그널 (SIGUSR1 ~ SIGUSR22)

그들 시그널은 다양한 다른 상활들을 보고하기 위해서 사용되어진다. 이들의 디폴트 동작은 프로세스가 종료되도록 하는 것이다.

SIGPIPE 시그널은 읽는 프로세스가 없는 상황에서의 PIPE에 대한 쓰기시 발생한다.

SIGUSR1 과 SIGUSR22 시그널들은 당신이 원하는 어떤 방법을 사용하지 못하도록 한다. 그들은 프로세스간 통신을 위해서 유용하다. 

그들 시그널을 보통 심각하기 때문에 당신은 그 시그널을 받은 프로그램에서 그들은 위한 시그널 처리를 해야할 것이다.



출처: http://ssambback.tistory.com/entry/Unix-or-Linux-별-프로그램-에러들 [Rehoboth.. 이곳에서 부터]

반응형
반응형

출처 : http://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&detail=1&pageno=0&wid=964&rssMode=1&wtype=0


정말로 좋은 글이 또 퍼옴. 두고두고 공부할 때 읽을 예정...





------------------------------------------------------------------------------------------------------------------------------------------------

사실, 처음 이 질문에 의문을 느꼈을 때 제 심중의 대답은 Port 수 제한이었습니다. unsigned short(2byte) 이니까 65535 일 텐데 그나마 시스템에서 사용하는 포트를 제외해야 하니 약 60K 정도는 생성할 수 있을 것이라는 계산이었습니다.

서버 한대에 6만 개의 클라이언트라면 그다지 나쁘지 않은 연결 수인 것 같았지만, 최근의 64비트 다중 코어/소켓을 장착한 고성능 서버들이 출현하는 상황에서 거의 무한대에 가까운 16byte 주소값을 갖는 IPv6에서도 포트를 나타내는 타입이 USHORT 인 것을 보고는 다소 놀랬습니다.

=== ws2ipdef.h ===
typedef struct sockaddr_in6 {
    ADDRESS_FAMILY sin6_family; // AF_INET6.
    USHORT sin6_port;           // Transport level port number.
    ULONG  sin6_flowinfo;       // IPv6 flow information.
    IN6_ADDR sin6_addr;         // IPv6 address.
    union {
        ULONG sin6_scope_id;     // Set of interfaces for a scope.
        SCOPE_ID sin6_scope_struct; 
    };
} SOCKADDR_IN6_LH, *PSOCKADDR_IN6_LH, FAR *LPSOCKADDR_IN6_LH;


여전히 미래에도 60K 동시 연결만을 제공한다는 걸까요?

도저히 그럴 수는 없다는 상식으로, 검색을 해보았습니다. 그런데... 꽤나 의외더군요. 이에 대한 의문을 갖는 사람도 별로 없었을 뿐더러, 대부분은 답변까지 포함해서 틀린 답들 뿐이었습니다. (일부 답변은 Windows 2000만 있었을 당시라서 그 때에는 맞는 답일 수 있습니다.)

이론상 접속 가능한 최대 인원은? 
; http://www.gpgstudy.com/forum/viewtopic.php?topic=5370

다시한번질문드립니다.소켓의 한계...한피씨의 서버용량은???
; http://www.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_qna&no=15833

소켓 생성시 최대개수는..... 얼마나..  
; http://www.devpia.com/Maeul/Contents/Detail.aspx?BoardID=50&MaeulNo=20&no=206826&ref=206665

Windows에서 열 수 있는 Socket 수 얻는 방법
; http://bspfp.pe.kr/63

WSAAsyncSelect 로가능한 소켓갯수는...
; http://www.tipssoft.com/bulletin/board.php?bo_table=QnA&wr_id=16299


사실, 검색도 힘들었는데... 디아블로인가... ^^; 게임에서 제공되는 소켓 아이템이라는 동일 이름 때문이었습니다. (다시 한번 놀랬지만, 게임 유저들의 그 참여/공유 정신은 대단한 것 같습니다. ^^)

다음 차례로, 외국 자료가 남았군요. 검색을 해보니, 진단이 딱 나옵니다.

One Million TCP Connections...
; http://www.serverframework.com/asynchronousevents/2010/12/one-million-tcp-connections.html


윈도우상에서의 이론 상 한계는 "16,777,214" 이라고 합니다. 이 정도면 결국 실질적인 한계가 문제인데, 아래의 글에서 잘 정리해 주고 있습니다.

How to support 10,000 or more concurrent TCP connections
; http://www.serverframework.com/asynchronousevents/2010/10/how-to-support-10000-concurrent-tcp-connections.html


  • Data copies
  • Context switches
  • Memory allocation
  • Lock contention


즉, 서버 스펙도 따라야 하고, 해당 응용 프로그램의 메모리/로직에 따라서 천차만별이 된다는 것이죠. ^^

참고로, 아래는 일반적인 threshold 값들인데 아마도 Windows Server 2003 기준의 값인 것 같습니다. 운영체제마다 변경된 부분이 있을 테니 적용할 때는 적절하게 감안을 해주셔야 할 것입니다.

Configure the max limit for concurrent TCP connections 
; http://smallvoid.com/article/winnt-tcpip-max-limit.html





그런데, 아직... 의문이 안 풀린 분들이 있을 텐데요. 과연 어떻게 포트 번호 범위를 넘어서는 16,777,214 값이 나오게 된 걸까요? 이에 대한 설명은 위에서 소개한 "One Million TCP Connections..." 글의 댓글에서 글쓴이가 쉽게 설명해 주고 있습니다.

No, that's a common misconception. You're limited to the local ports when making outbound connections as each connection consumes a local port and they are limited to 65535 as you point out and when you take into account the number of ports already in use for other services and any connections currently in TIME_WAIT the maximum number of outbound ports is usually at most 50k.

Inbound ports are identified by a tuple that consists of the local ip and port and the remote ip and port and so are not limited in the same way. I've run tests whereby a simple server on very modest hardware supported more than 70,000 concurrent active connections - the test server and client that I used can be found here: http://www.lenholgate.com/archives/000568.html



오~~~ 역시 머리 좋은 사람들은 다르군요. ^^ 어차피 내부에서 해당 소켓을 식별만 하면 되는데 굳이 2바이트 정수로 제한할 필요없이 구분키의 범위를 연결을 시도한 측의 IP/Port를 함께 포함하니 자연스럽게 65,535 개의 한계가 없어져버립니다. 실제로 글쓴이는 760 MB 메모리만을 가진 Windows Server 2003 시스템으로 7만 개의 동시 연결을 테스트했다고 합니다.

재미있군요. 직접 테스트 해보실 분들 계신가요? 700 MB 정도에 7만 개면, 24 GB 메모리면 테스트에 사용한 동일한 서버 프로그램으로 210만 개는 무난하게 나온다는 얘기가 되는 군요. 그럼, 서버는 그 정도 사양으로 한 대 준비하면 될 것 같고. 반면에 클라이언트는 제법 준비를 해둬야 합니다. 왜냐 하면 클라이언트 측은 여전히 65,535 포트 범위 제한이 있기 때문에, 100만개 연결 테스트만 해도 20 대 정도가 넘게 필요합니다. Virtual NIC의 특별한 제한이 없다면 가상 PC를 20개 정도 마련해야 겠군요. (참고로, 가정용 무선 Access Point로는 네트워크 연결 테스트하지 마세요. ^^ 제 경우에는 천 개만 넘어도 네트워크가 멈춰버렸습니다.)

혹시, 환경 구성해서 테스트 하시는 분이 계시면 결과 좀 공유 부탁드리겠습니다. ^^

반응형
반응형

출처 : http://d2.naver.com/helloworld/47667


정말로 좋은 글이 있어서 천천히 두고두고 공부할려고 파왔음...





TCP/IP 없는 인터넷 서비스는 상상할 수 없습니다. 우리가 개발하고 사용하는 모든 인터넷 서비스는 TCP/IP라는 튼튼한 토대에 기반하고 있습니다. 어떻게 네트워크를 통해 데이터가 오가는지를 이해하면, 튜닝 등을 통한 성능 개선이나 트러블 슈팅, 신기술 도입 등에 많은 도움이 됩니다.

이 글에서는 Linux 운영체제와 하드웨어 레이어에서의 데이터 흐름과 제어 흐름을 바탕으로 네트워크 스택에 대한 전반적인 작동 방식을 알아보겠습니다.

TCP/IP의 중요한 성질

데이터의 순서가 바뀌지 않으면서 데이터가 유실되지 않도록 가급적 빠르게 데이터를 보내려면 네트워크 프로토콜을 어떻게 설계해야 할까? TCP/IP는 이런 고민 아래 설계된 것이다. 다음은 스택을 이해하는데 필요한 TCP/IP의 중요한 성질이다.


TCP와 IP

엄밀히 말해 TCP와 IP는 서로 다른 레이어의 것이라 분리해서 이해하는 것이 옳지만, 이해의 편의상 여기서는이 장에서는 둘을 분리하지 않고 설명한다.


1. Connection oriented

두 개 엔드포인트(로컬, 리모트) 사이에 연결을 먼저 맺고 데이터를 주고받는다. 여기서 'TCP 연결 식별자'는 두 엔드포인트의 주소를 합친 것으로, <로컬 IP 주소, 로컬 포트번호, 리모트 IP 주소, 리모트 포트번호> 형태이다.

2. Bidirectional byte stream

양방향 데이터 통신을 하고, 바이트 스트림을 사용한다.

3. In-order delivery

송신자(sender)가 보낸 순서대로 수신자(receiver)가 데이터를 받는다. 이를 위해서는 데이터의 순서가 필요하다. 순서를 표시하기 위해 32-bit 정수 자료형을 사용한다.

4. Reliability through ACK

데이터를 송신하고 수신자로부터 ACK(데이터 받았음)를 받지 않으면, 송신자 TCP가 데이터를 재전송한다. 따라서 송신자 TCP는 수신자로부터 ACK를 받지 않은 데이터를 보관한다(buffer unacknowledged data).

5. Flow control

송신자는 수신자가 받을 수 있는 만큼 데이터를 전송한다. 수신자가 자신이 받을 수 있는 바이트 수 (사용하지 않은 버퍼 크기, receive window)를 송신자에게 전달한다. 송신자는 수신자 receive window가 허용하는 바이트 수만큼 데이터를 전송한다.

6. Congestion control

네트워크 정체를 방지하기 위해 receive window와 별도로 congestion window를 사용하는데 이는 네트워크에 유입되는 데이터양을 제한하기 위해서이다. Receive window와 마찬가지로 congestion window가 허용하는 바이트 수만큼 데이터를 전송하며 여기에는 TCP Vegas, Westwood, BIC, CUBIC 등 다양한 알고리즘이 있다. Flow control과 달리 송신자가 단독으로 구현한다.

데이터 전송

이름이 설명하듯, 네트워크 스택에는 여러 레이어(layer)가 있다. 어떤 레이어가 있는지는 그림 2에서 알 수 있다.

여러 레이어가 있지만, 크게 유저(user) 영역, 커널(kernel) 영역, 디바이스로(device) 영역으로 나눌 수 있다. 유저 영역과 커널 영역에서의 작업은 CPU가 수행한다. 이 유저 영역과 커널 영역은 디바이스 영역과 구별하기 위해 호스트(host)라고 부른다. 여기서 디바이스는 패킷을 송수신하는 NIC(Network Interface Card)이다. 흔히 부르는 랜카드보다 더 정확한 용어이다.

networkstack1

그림 1 데이터 전송 시 TCP/IP 네트워크 스택의 각 레이어 별 동작 과정

유저 영역부터 밑으로 내려가 보자. 우선 애플리케이션이 전송할 데이터를 생성하고(그림 1에서 User data 상자), write 시스템 콜을 호출해서 데이터를 보낸다. 소켓(그림 2에서 fd)은 이미 생성되어 연결되어 있다고 가정한다. 시스템 콜을 호출하면 커널 영역으로 전환된다.

Linux나 Unix를 포함한 POSIX 계열 운영체제는 소켓을 file descriptor로 애플리케이션에 노출한다. 이런 POSIX 계열의 운영체제에서 소켓은 파일의 한 종류다. 파일(file) 레이어는 단순한 검사만 하고 파일 구조체에 연결된 소켓 구조체를 사용해서 소켓 함수를 호출한다.

커널 소켓은 두 개의 버퍼를 가지고 있다. 송신용으로 준비한 send socket buffer, 수신용으로 준비한 receive socket buffer이다. Write 시스템 콜을 호출하면 유저 영역의 데이터가 커널 메모리로 복사되고, send socket buffer의 뒷부분에 추가된다. 순서대로 전송하기 위해서다. 그림에서 옅은 회식 상자가 이미 socket buffer에 존재하는 데이터를 의미한다. 이 다음으로 TCP를 호출한다.

소켓과 연결된 TCP Control Block(TCB) 구조체가 있다. TCB에는 TCP 연결 처리에 필요한 정보가 있다. TCB에 있는 데이터는 connection state(LISTEN, ESTABLISHED, TIME_WAIT 등), receive window, congestion window, sequence 번호, 재전송 타이머 등이다.

현재 TCP 상태가 데이터 전송을 허용하면 새로운 TCP segment, 즉 패킷을 생성한다. Flow control 같은 이유로 데이터 전송이 불가능하면 시스템 콜은 여기서 끝나고, 유저 모드로 돌아간다(즉, 애플리케이션으로 제어권이 넘어간다).

TCP segment에는 TCP 헤더와 페이로드(payload)가 있다. 페이로드에는 ACK를 받지 않은 send socket buffer에 있는 데이터가 담겨 있다. 페이로드의 최대 길이는 receive window, congestion window, MSS(Maximum Segment Size) 중 최대 값이다.

그리고 TCP checksum을 계산한다. 이 checksum 계산에는 pseudo 헤더 정보(IP 주소들, segment 길이, 프로토콜 번호)를 포함시킨다. 여기서 TCP 상태에 따라 패킷을 한 개 이상 전송할 수 있다.

사실 요즘의 네트워크 스택에서는 checksum offload 기술을 사용하기 때문에, 커널이 직접 TCP checksum을 계산하지 않고 대신 NIC가 checksum을 계산한다. 여기서는 설명의 편의를 위해 커널이 checksum을 계산한다고 가정한다.

생성된 TCP segment는 IP 레이어로 이동한다(내려 간다). IP 레이어에서는 TCP segment에 IP 헤더를 추가하고, IP routing을 한다. IP routing이란 목적지 IP 주소(destination IP)로 가기 위한 다음 장비의 IP 주소(next hop IP)를 찾는 과정을 말한다.

IP 레이어에서 IP 헤더 checksum을 계산하여 덧붙인 후, Ethernet 레이어로 데이터를 보낸다.

Ethernet 레이어는 ARP(Address Resolution Protocol)를 사용해서 next hop IP의 MAC 주소를 찾는다. 그리고 Ethernet 헤더를 패킷에 추가한다. Ethernet 헤더까지 붙으면 호스트의 패킷은 완성이다.

IP routing을 하면 그 결과물로 next hop IP와 해당 IP로 패킷 전송할 때 사용하는 인터페이스(transmit interface, 혹은 NIC)를 알게 된다. 따라서 transmit NIC의 드라이버를 호출한다.

만약 tcpdumpWireshark 같은 패킷 캡처 프로그램이 작동 중이면 커널은 패킷 데이터를 프로그램이 사용하는 메모리 버퍼에 복사한다. 수신도 마찬가지로 드라이버 바로 위에서 패킷을 캡처한다. 대개 traffic shaper 기능도 이 레이어에서 동작하도록 구현되어있다.

드라이버는 NIC 제조사가 정의한 드라이버-NIC 통신 규약에 따라 패킷 전송을 요청한다.

NIC는 패킷 전송 요청을 받고, 메인 메모리에 있는 패킷을 자신의 메모리로 복사하고, 네트워크 선으로 전송한다. 이때 Ethernet 표준에 따라 IFG(Inter-Frame Gap), preamble, 그리고 CRC를 패킷에 추가한다. IFG, preamble은 패킷의 시작을 판단하기 위해 사용하고(네트워킹 용어로는 framing), CRC는 데이터 보호를 위해 사용한다(TCP, IP checksum과 같은 용도이다). 패킷 전송은 Ethernet의 물리적 속도, 그리고 Ethernet flow control에 따라 전송할 수 있는 상황일 때 시작된다. 회의장에서 발언권을 얻고 말하는 것과 비슷하다.

NIC가 패킷을 전송할 때 NIC는 호스트 CPU에 인터럽트(interrupt)를 발생시킨다. 모든 인터럽트에는 인터럽트 번호가 있으며, 운영체제는 이 번호를 이용하여 이 인터럽트를 처리할 수 있는 적합한 드라이버를 찾는다. 드라이버는 인터럽트를 처리할 수 있는 함수(인터럽트 핸들러)를 드라이브가 가동되었을 때 운영체제에 등록해둔다. 운영체제가 핸들러를 호출하고, 핸들러는 전송된 패킷을 운영체제에 반환한다.

지금까지 설명한 것은 애플리케이션에서 쓰기를 하였을 때 데이터가 커널과 디바이스를 거쳐 전송되는 과정이다. 그런데 애플리케이션이 쓰기 요청을 직접적으로 하지 않아도 커널이 TCP를 호출해서 패킷을 전송하는 경우가 있다. 예를 들어 ACK을 받아 receive window가 늘어나면 socket buffer에 남아있는 데이터를 포함한 TCP segment를 생성하여 상대편에 전송한다.

데이터 수신

이제 어떻게 데이터를 수신하는지 알아보도록 하자. 패킷이 외부에서 도착했을 때 어떻게 작동하는지에 대한 것이다. 그림 3에서 네트워크 스택이 수신한 패킷을 처리하는 과정을 알 수 있다.

networkstack2

그림 2 데이터 수신 시 TCP/IP 네트워크 스택의 각 레이어 별 동작 과정

우선 NIC가 패킷을 자신의 메모리에 기록한다. CRC 검사로 패킷이 올바른지 검사하고, 호스트의 메모리버퍼로 전송한다. 이 버퍼는 드라이버가 커널에 요청하여 패킷 수신용으로 미리 할당한 메모리이고, 할당을 받은 후 드라이버는 NIC에 메모리 주소와 크기를 알려 준다. NIC가 패킷을 받았는데, 드라이버가 미리 할당해 놓은 호스트 메모리 버퍼가 없으면 NIC가 패킷을 버릴 수 있다 (packet drop).

패킷을 호스트 메모리로 전송한 후, NIC가 호스트운영체제에 인터럽트를 보낸다.

드라이버가 새로운 패킷을 보고 자신이 처리할 수 있는 패킷인지 검사한다. 여기까지는 제조사가 정의한 드라이버-NIC 통신 규약을 사용한다.

드라이버가 상위 레이어로 패킷을 전달하려면 운영체제가 이해할 수 있도록, 받은 패킷을 운영체제가 사용하는 패킷 구조체로 포장해야 한다. 예를 들어, Linux의 sk_buff, BSD 계열 커널의 mbuf, 그리고 Microsoft Windows의 NET_BUFFER_LIST가 운영체제의 패킷 구조체이다. 드라이버는 이렇게 포장한 패킷을 상위 레이어로 전달한다.

Ethernet 레이어에서도 패킷이 올바른지 검사하고, 상위 프로토콜(네트워크 프로토콜)을 찾는다(de-multiplex). 이때 Ethernet 헤더의 ethertype 값을 사용한다. IPv4 ethertype은 0x0800이다. Ethernet 헤더를 제거하고 IP 레이어로 패킷을 전달한다.

IP 레이어에서도 패킷이 올바른지 검사한다. IP 헤더 checksum을 확인하는 것이다. 논리적으로 여기서 IP routing을 해서 패킷을 로컬 장비가 처리해야 하는지, 아니면 다른 장비로 전달해야 하는지 판단한다. 로컬 장비가 처리해야 하는 패킷이면 IP 헤더의 proto 값을 보고 상위 프로토콜(트랜스포트 프로토콜)을 찾는다. TCP proto 값은 6이다. IP 헤더를 제거하고 TCP 레이어로 패킷을 전달한다.

하위 레이어에서와 마찬가지로 TCP 레이어에서도 패킷이 올바른지 검사한다. TCP checksum도 확인한다. 앞서 언급했듯이 요즘의 네트워크 스택에는 checksum offload 기술이 적용되어 있기 때문에 커널이 checksum을 직접 계산하지 않는다.

다음으로 패킷이 속하는 연결, 즉 TCP control block을 찾는다. 이때 패킷의 <소스 IP, 소스 port, 타깃 IP, 타깃 port>를 식별자로 사용한다. 연결을 찾으면 프로토콜을 수행해서 받은 패킷을 처리한다. 새로운 데이터를 받았다면, 데이터를 receive socket buffer에 추가한다. TCP 상태에 따라 새로운 TCP 패킷(예를 들어 ACK 패킷)을 전송할 수 있다. 여기까지 해서 TCP/IP 수신 패킷 처리 과정이 끝나게 된다.

Receive socket buffer 크기가 결국은 TCP의 receive window이다. 어느 지점까지는 receive window가 크면 TCP throughput이 증가한다. 예전에는 socket buffer 크기를 애플리케이션이나 운영체제 설정에서 조절하고는 했다. 최신 네트워크 스택은 receive socket buffer 크기, 즉 receive window를 자동으로 조절하는 기능을 가지고 있다.

이후 애플리케이션이 read 시스템 콜을 호출하면 커널 영역으로 전환되고, socket buffer에 있는 데이터를 유저 공간의 메모리로 복사해 간다. 복사한 데이터는 socket buffer에서 제거한다. 그리고 TCP를 호출한다. TCP는 socket buffer에 새로운 공간이 생겼기 때문에 receive window를 증가시킨다. 그리고 프로토콜 상태에 따라 패킷을 전송한다. 패킷 전송이 없으면 시스템 콜이 종료된다.

네트워크 스택 발전 방향

지금까지 설명한 네트워크 스택 레이어가 하는 일은 가장 기본적인 기능이다. 1990년대 초반의 네트워크 스택은 이보다 약간 더 기능이 많은 정도였다. 하지만 요즘의 최신 네트워크 스택은 더 많은 기능을 가지고 있고, 따라서 네트워크 스택 구현체의 복잡성도 증가했다.

최신의 네트워크 스택을 목적에 따라 구분해 보면 다음과 같다.

패킷 처리 과정 조작 기능

Netfilter(방화벽, NAT 등), traffic control 같은 기능이다. 기본 처리 흐름에 사용자가 제어할 수 있는 코드를 삽입해서 사용자 설정에 따라 다양한 효과를 낸다.

프로토콜 성능

주어진 네트워크 환경에서 TCP 프로토콜이 달성할 수 있는 throughput, latency, stability 등의 개선을 목표로 한다. 다양한 congestion control 알고리즘들과 SACK 같은 TCP 추가 기능이 대표적인 예이다. 프로토콜 개선 사항은 이 글의 범위 바깥이라 여기서는 다루지 않겠다.

패킷 처리 효율

한 장비가 패킷을 처리하는데 소요되는 CPU cycle, 메모리 사용량, 메모리 접근 수 등을 줄여서 초당 처리할 수 있는 최대 패킷 수를 개선하는 것을 목표로 한다. 장비 내부에서의 레이턴시(latency)를 줄이는 것을 포함한 여러 시도가 있었다. 스택 병렬처리, header prediction, zero-copy, single-copy, checksum offload, TSO, LRO, RSS 등 여러 가지가 있다.

스택 내부 제어 흐름(control flow)

이제 Linux 네트워크 스택의 내부 흐름을 좀더 깊게 살펴보자. 네트워크 스택이 아닌 서브시스템과 마찬가지로, 네트워크 스택은 기본적으로 이벤트 발생에 반응하는 event-driven 방식으로 작동한다. 따라서 스택 수행을 위한 별도 스레드는 없다. 그림 2와 그림 3은 제어 흐름을 매우 단순화한 것이고, 그림 4에서 좀 더 정확한 제어 흐름을 볼 수 있다.

networkstack3

그림 3 스택 내부 제어 흐름

그림 3의 (1)은 애플리케이션이 시스템 콜을 호출하여 TCP를 수행(사용)하는 경우다. 예를 들어, read 시스템 콜과 write 시스템 콜을 호출하고 TCP를 수행한다. 하지만 패킷 전송은 없다.

(2)는 (1)과 같은데, TCP 수행 결과 패킷 전송이 필요한 경우다. 패킷을 생성해서 드라이버로 패킷을 내려 보낸다. 드라이버의 앞 부분에는 큐(queue)가 있다. 패킷은 우선 큐에 들어가고, 큐 구현체가 패킷이 드라이버로 전달되는 시점을 결정한다. Linux의 qdisc(queue discipline)가 이것이다. Linux traffic control 기능은 qdisc를 조작하는 것이다. 기본으로 사용하는 qdisc는 단순한 FIFO(first-in-first-out) 큐이다. 다른 qdisc를 사용하면 인위적인 패킷 유실, 패킷 지연, 전송 속도 제한 등 여러 가지 효과를 달성할 수 있다. (1), (2)에서는 애플리케이션의 프로세스 스레드가 드라이버까지 실행한다.

(3) 흐름은 TCP가 사용하는 타이머가 만료된 경우다. 예를 들어, TIME_WAIT 타이머가 만료되면 TCP를 호출해서 연결을 삭제한다.

(4) 흐름은 (3)과 같이 TCP가 사용하는 타이머가 만료된 경우인데, TCP 수행 결과 패킷 전송이 필요한 경우다. 예를 들어 재전송 타이머(retransmit timer)가 만료되면, ACK를 받지 못한 패킷을 전송한다.

(3), (4) 흐름은 타이머 인터럽트를 처리한 softirq가 실행되는 과정이다.

NIC 드라이버가 인터럽트를 받으면 전송된 패킷을 반환한다(free). 대개 여기서 드라이버 실행이 끝난다. (5) 흐름은 transmit queue에 패킷이 적체된 경우다. 드라이버가 softirq를 요청하고, softirq 핸들러가 transmit queue를 실행해서 적체된 패킷을 드라이버로 보낸다.

NIC 드라이버가 인터럽트를 받고 새로 수신된 패킷을 발견하면 softirq를 요청한다. 수신 패킷을 처리하는 softirq가 드라이버를 호출해서 수신된 패킷을 상위 레이어로 전달한다. Linux는 이와 같이 수신 패킷을 처리하는 것을 NAPI(new API)라고 부른다. 드라이버가 상위 레이어로 직접 전달하지 않고, 상위 레이어가 직접 패킷을 가져가기 때문에 polling과 유사하다. 실제 코드는 NAPI poll 혹은 poll이라 부른다.

(6)은 TCP까지 수행한 경우, (7)은 추가 패킷 전송이 필요한 경우를 보여준다. (5), (6), (7) 모두 NIC 인터럽트를 처리한 softirq가 실행한다.

인터럽트와 수신 패킷 처리

인터럽트 처리는 복잡하지만 패킷 수신 처리에 따른 성능 문제를 이해하기 위해 필요하다. 그림 4에서 인터럽트 처리 과정을 볼 수 있다.

networkstack4

그림 4 인터럽트, softirq, 그리고 수신 패킷 처리

CPU 0이 애플리케이션 프로그램(user program)을 실행하고 있다고 가정하자. 이때 NIC가 패킷을 수신하고 CPU 0을 인터럽트한다. CPU는 커널 인터럽트(흔히 irq라고 부른다) 핸들러를 실행한다. 이 핸들러가 인터럽트 번호를 보고 드라이버 인터럽트 핸들러를 호출한다. 드라이버는 전송된 패킷은 반환하고, 수신된 패킷을 처리하기 위해 napi_schedule() 함수를 호출한다. 이 함수가 softirq(소프트웨어 인터럽트)를 요청한다.

드라이버 인터럽트 핸들러의 실행이 종료되면 커널 핸들러로 제어권이 돌아간다. 커널 핸들러가 softirq에 대한 인터럽트 핸들러를 실행시킨다.

Interrupt context가 실행되었으니 softirq context가 실행될 차례이다. Interrupt context와 softirq context가 실행되는 스레드는 같다. 하지만 스택이 서로 다르다. 그리고 interrupt context는 하드웨어 인터럽트를 차단하지만, softirq context는 하드웨어 인터럽트를 허용한다.

수신 패킷을 처리하는 softirq 핸들러는 net_rx_action() 함수이다. 이 함수는 드라이버의 poll() 함수를 호출한다. poll() 함수는 netif_receive_skb() 함수를 호출해서 수신 패킷을 한 개씩 상위 레이어로 보낸다. softirq 처리가 종료되면, 애플리케이션은 시스템 콜을 요청하기 위하여 중단했던 지점부터 다시 수행을 재개한다.

따라서 인터럽트를 받은 CPU가 수신 패킷을 처음부터 끝까지 처리한다. Linux, BSD, Microsoft Windows 모두 기본으로 이와 같이 작동한다.

패킷 수신을 많이 하는 서버 CPU 사용률을 보면 한 CPU만 열심히 softirq를 실행하는 현상을 종종 확인할 수 있다. 지금까지 설명한 수신 패킷 처리 방식 때문에 발생하는 현상이다. 이 문제를 풀기 위해 multi-queue NIC, RSS, RPS가 나왔다.

데이터 구조체

중요한 데이터 구조체 몇 개를 살펴보고 실제 코드를 따라가 보자.

sk_buff 구조체

첫째, 패킷을 의미하는 sk_buff 구조체 혹은 skb 구조체가 있다. 그림 5는 sk_buff 구조체의 일부를 보여준다. 기능이 발전되면서 이보다 더 복잡해졌지만 기본적으로 필요한 기능은 누구나 생각할 수 있는 것들이다.

networkstack5

그림 5 패킷 구조체 sk_buff

패킷 데이터, 메타 데이터 포함

패킷 데이터를 구조체가 직접 포함하고 있거나, 포인터를 사용해서 참조하고 있다. 그림 5에서는 패킷 일부는 (Ethernet부터 buffer까지) 데이터 포인터를 이용해 참조하고 있고, 추가 데이터(frags)는 실제 페이지를 참조하고 있다.

메타 데이터 영역에는 헤더, 페이로드 길이 등 필요한 정보를 저장한다. 예를 들어, 그림 5에서 볼 수 있는 mac_header에는 Ethernet 헤더, network_header에는 IP 헤더, transport_header에는 TCP 헤더 시작 위치를 가리키고 있는 포인터 데이터가 있다. 이런 방식은 TCP 프로토콜 매우 편리하게 처리할 수 있게 한다.

헤더 추가, 삭제

네트워크 스택의 각 레이어를 왔다갔다하며 헤더를 추가, 삭제한다. 효율적으로 처리하기 위해 포인터들을 사용한다. 예를 들어, Ethernet 헤더를 제거하려면, head 포인터를 증가하면 된다.

패킷 결합, 분리

Socket buffer에 패킷 페이로드 데이터를 추가, 삭제, 또는 패킷 체인 같은 작업을 효율적으로 수행하기 위해 linked list를 사용한다. next, prev 포인터가 이 용도로 사용된다.

빠른 할당(allocation)과 반환(free)

패킷을 생성할 때마다 구조체를 할당하기 때문에 빠른 allocator를 사용한다. 예를 들어, 10 Gigabit Ethernet 속도로 데이터를 전송하면 초당 1백만 패킷 이상을 생성, 제거해야 한다.

TCP control block

둘째, TCP 연결을 대표하는 구조체가 있다. 앞서 추상적으로 TCP control block이라 불렀는데, Linux는 tcp_sock을 사용한다. 그림 7에서 file, socket과 tcp_sock 등이 어떤 관계에 있는지 알 수 있다.

networkstack6

그림 6 TCP 연결 구조체

시스템 콜이 발생하면 시스템 콜을 호출한 애플리케이션이 사용하는 file descriptor에 있는 file을 찾는다. Unix 계열 운영체제에서는 socket, 저장을 위한 일반 files system 용 file, 디바이스 등 여러 가지를 모두 file로 추상화한다. 따라서 file 구조체는 최소한의 정보만 포함한다. Socket의 경우 별도 socket 구조체가 소켓 관련 정보를 저장하고, file은 socket을 포인터로 참조한다. Socket은 다시 tcp_sock을 참조한다. tcp_sock은 sock, inet_sock 등으로 세분화되어 있는데, TCP 외의 다양한 프로토콜을 지원하기 위해서다. 일종의 폴리모피즘과 비슷하다고 보면 되겠다.

tcp_sock에는 TCP 프로토콜이 사용하는 모든 상태 정보를 저장한다. 예를 들어, 시퀀스 번호, receive window, congestion control, 재전송 타이머 등 정보가 모두 모여 있다.

Send socket buffer와 receive socket buffer는 sk_buff 리스트이고, tcp_sock을 포함한다. IP routing 결과물인 dst_entry도 참조해서 매번 routing하지 않도록 한다. dst_entry를 사용해서 ARP 결과, 즉 목적지 MAC 주소도 쉽게 찾는다. dst_entry는 routing table의 일부이다. routing table의 구조는 상당히 복잡해서 이 글에서는 다루지 않겠다. dst_entry를 사용해서 패킷 송신에 사용해야 하는 NIC를 찾는다. NIC는 net_device 구조체로 표현한다.

따라서 file만 찾으면 TCP 연결을 처리하는데 필요한 모든 구조체(file부터 드라이버까지)를 포인터로 쉽게 찾을 수 있다. 이들 구조체의 크기가 TCP 연결 하나가 사용하는 메모리의 양이다. 메모리의 양은 수 KB 정도(패킷 데이터 제외)다. 메모리 사용량도 기능이 추가되면서 꾸준히 증가했다.

마지막으로 TCP 연결 lookup table이 있다. 해시 테이블(hash table)인데, 수신된 패킷이 속하는 TCP 연결을 찾는데 사용한다. 해시 값은 패킷의 <소스 IP, 타깃 IP, 소스 port, 타깃 port>를 입력 데이터로 하고, Jenkins hash 알고리즘을 사용해서 계산한다. 해시 함수는 해시 테이블 공격에 대한 방어를 고려해서 선택했다고 한다.

코드 따라가기: 데이터 전송

실제 Linux 커널 소스 코드를 따라가며 스택이 수행하는 주요 작업을 알아보자. 자주 사용하는 경로 두 개만 살펴보겠다.

우선 애플리케이션이 write 시스템 콜을 호출할 때 데이터가 전송되는 경로를 보자.

SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, ...)  
{
struct file *file;  
[...]
file = fget_light(fd, &fput_needed);  
[...] ===>
ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos);

struct file_operations {  
[...]
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, ...)  
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, ...)  
[...]
};

static const struct file_operations socket_file_ops = {  
[...]
.aio_read = sock_aio_read,
.aio_write = sock_aio_write,
[...]
};

write 시스템 콜을 호출하면 커널이 파일 레이어의 write() 함수를 수행한다. 우선 file descriptor fd의 실제 file 구조체를 가져온다. 그리고 aio_write를 호출한다. 이것은 함수 포인터이다. file 구조체를 보면 file_operations 구조체 포인터가 있는데, 이 구조체는 흔히 부르는 function table이고, aio_read, aio_write등 함수 포인터를 포함한다. 실제 소켓용 table은 socket_file_ops이다. 소켓이 사용하는 aio_write 함수는 sock_aio_write이다. Function table은 Java 인터페이스와 유사한 용도로 사용한다. 커널이 코드 추상화나 리팩토링(refactoring)을 할 때 흔히 사용한다.

static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, ..)  
{
[...]
struct socket *sock = file->private_data;  
[...] ===>
return sock->ops->sendmsg(iocb, sock, msg, size);

struct socket {  
[...]
struct file *file;  
struct sock *sk;  
const struct proto_ops *ops;  
};

const struct proto_ops inet_stream_ops = {  
.family = PF_INET,
[...]
.connect = inet_stream_connect,
.accept = inet_accept,
.listen = inet_listen, .sendmsg = tcp_sendmsg,
.recvmsg = inet_recvmsg,
[...]
};

struct proto_ops {  
[...]
int (*connect) (struct socket *sock, ...)  
int (*accept) (struct socket *sock, ...)  
int (*listen) (struct socket *sock, int len);  
int (*sendmsg) (struct kiocb *iocb, struct socket *sock, ...)  
int (*recvmsg) (struct kiocb *iocb, struct socket *sock, ...)  
[...]
};

sock_aio_write 함수는 file에서 socket 구조체를 가져오고 sendmsg를 호출한다. 이것도 함수 포인터이다. Socket 구조체는 proto_ops function table을 포함한다. IPv4 TCP가 구현한 proto_ops는 inet_stream_ops이고, sendmsg는 tcp_sendmsg가 구현하고 있다.

int tcp_sendmsg(struct kiocb *iocb, struct socket *sock,  
struct msghdr *msg, size_t size)  
{
struct sock *sk = sock->sk;  
struct iovec *iov;  
struct tcp_sock *tp = tcp_sk(sk);  
struct sk_buff *skb;  
[...]
mss_now = tcp_send_mss(sk, &size_goal, flags);

/* Ok commence sending. */
iovlen = msg->msg_iovlen;  
iov = msg->msg_iov;  
copied = 0;  
[...]
while (--iovlen >= 0) {  
int seglen = iov->iov_len;  
unsigned char __user *from = iov->iov_base;

iov++;  
while (seglen > 0) {  
int copy = 0;  
int max = size_goal;  
[...]
skb = sk_stream_alloc_skb(sk,  
select_size(sk, sg),  
sk->sk_allocation);  
if (!skb)  
goto wait_for_memory;  
/*
* Check whether we can use HW checksum.
*/
if (sk->sk_route_caps & NETIF_F_ALL_CSUM)  
skb->ip_summed = CHECKSUM_PARTIAL;  
[...]
skb_entail(sk, skb);  
[...]
/* Where to copy to? */
if (skb_tailroom(skb) > 0) {  
/* We have some space in skb head. Superb! */
if (copy > skb_tailroom(skb))  
copy = skb_tailroom(skb);  
if ((err = skb_add_data(skb, from, copy)) != 0)  
goto do_fault;  
[...]
if (copied)  
tcp_push(sk, flags, mss_now, tp->nonagle);  
[...]
}

tcp_sengmsg는 socket에서 tcp_sock, 즉 TCP control block을 가져오고, 애플리케이션이 전송 요청한 데이터를 send socket buffer로 복사한다. 데이터를 sk_buff로 복사할 때 sk_buff 하나가 몇 바이트를 포함해야 할까? 실제 패킷을 생성하는 코드를 돕기 위해 sk_buff 하나가 MSS(tcp_send_mss) 바이트가 포함되도록 복사한다. MSS는 'Maximum Segment Size'로 TCP 패킷 한 개가 포함하는 최대 페이로드 크기다. TSO, GSO를 사용하면 sk_buff 한 개가 MSS보다 더 많은 데이터를 저장하는데, 이 부분은 다음 기회에 설명하겠다.

sk_stream_alloc_skb 함수가 새로운 sk_buff를 생성하고, skb_entail이 send_socket_buffer 꼬리에 새로운 sk_buff를 추가한다. skb_add_data 함수가 실제 애플리케이션 데이터를 sk_buff의 데이터 버퍼로 복사한다. 이 과정(sk_buff 생성, send socket buffer에 추가)을 여러 번 반복해서 모든 데이터를 복사한다. 결국은 MSS 크기의 sk_buff들이 send socket buffer에 리스트로 묶여 있는 모양이 된다. 끝으로 tcp_push를 호출해서 지금 전송할 수 있는 데이터를 패킷으로 만들어서 전송한다.

static inline void tcp_push(struct sock *sk, int flags, int mss_now, ...)  
[...] ===>
static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, ...)  
int nonagle,  
{
struct tcp_sock *tp = tcp_sk(sk);  
struct sk_buff *skb;  
[...]
while ((skb = tcp_send_head(sk))) {  
[...]
cwnd_quota = tcp_cwnd_test(tp, skb);  
if (!cwnd_quota)  
break;

if (unlikely(!tcp_snd_wnd_test(tp, skb, mss_now)))  
break;  
[...]
if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp)))  
break;

/* Advance the send_head. This one is sent out.
* This call will increment packets_out.
*/
tcp_event_new_data_sent(sk, skb);  
[...]

tcp_push 함수는 TCP가 허용하는 만큼 send socket buffer의 sk_buff를 차례대로 전송한다. 우선 tcp_send_head 호출해서 socket buffer의 가장 앞에 있는 sk_buff를 가져오고, tcp_cwnd_test, tcp_snd_wnd_test로 congestion window과 수신 TCP의 receive window가 새로운 패킷 전송을 허용하는지 확인한다. 그리고 tcp_transmit_skb 함수를 호출해서 실제 패킷을 생성한다.

static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb,  
int clone_it, gfp_t gfp_mask)  
{
const struct inet_connection_sock *icsk = inet_csk(sk);  
struct inet_sock *inet;  
struct tcp_sock *tp;  
[...]


if (likely(clone_it)) {  
if (unlikely(skb_cloned(skb)))  
skb = pskb_copy(skb, gfp_mask);  
else  
skb = skb_clone(skb, gfp_mask);  
if (unlikely(!skb))  
return -ENOBUFS;  
}

[...]
skb_push(skb, tcp_header_size);  
skb_reset_transport_header(skb);  
skb_set_owner_w(skb, sk);

/* Build TCP header and checksum it. */
th = tcp_hdr(skb);  
th->source = inet->inet_sport;  
th->dest = inet->inet_dport;  
th->seq = htonl(tcb->seq);  
th->ack_seq = htonl(tp->rcv_nxt);  
[...]
icsk->icsk_af_ops->send_check(sk, skb);  
[...]
err = icsk->icsk_af_ops->queue_xmit(skb);  
if (likely(err <= 0))  
return err;

tcp_enter_cwr(sk, 1);

return net_xmit_eval(err);  
}

tcp_transmit_skb은 주어진 sk_buff의 복사본(pskb_copy)을 만든다. 이때 애플리케이션 데이터 전체를 복사하지 않고, 메타데이터만 복사한다. 그리고 skb_push를 호출해서 헤더 영역을 확보하고, 헤더 필드 값을 기록한다. send_check은 TCP checksum을 계산한다. Checksum offload를 사용하면 페이로드 데이터는 계산하지 않는다. 마지막으로, queue_xmit를 호출해서 IP 레이어로 패킷을 보낸다. IPv4 용 queue_xmit은 ip_queue_xmit 함수가 구현한다.

int ip_queue_xmit(struct sk_buff *skb)  
[...]
rt = (struct rtable *)__sk_dst_check(sk, 0);  
[...]
/* OK, we know where to send it, allocate and build IP header. */
skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));  
skb_reset_network_header(skb);  
iph = ip_hdr(skb);  
*((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
if (ip_dont_fragment(sk, &rt->dst) && !skb->local_df)  
iph->frag_off = htons(IP_DF);  
else  
iph->frag_off = 0;  
iph->ttl = ip_select_ttl(inet, &rt->dst);  
iph->protocol = sk->sk_protocol;  
iph->saddr = rt->rt_src;  
iph->daddr = rt->rt_dst;  
[...]
res = ip_local_out(skb);  
[...] ===>
int __ip_local_out(struct sk_buff *skb)  
[...]
ip_send_check(iph);  
return nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, skb, NULL,  
skb_dst(skb)->dev, dst_output);  
[...] ===>
int ip_output(struct sk_buff *skb)  
{
struct net_device *dev = skb_dst(skb)->dev;  
[...]
skb->dev = dev;  
skb->protocol = htons(ETH_P_IP);

return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, NULL, dev,  
ip_finish_output,  
[...] ===>
static int ip_finish_output(struct sk_buff *skb)  
[...]
if (skb->len > ip_skb_dst_mtu(skb) && !skb_is_gso(skb))  
return ip_fragment(skb, ip_finish_output2);  
else  
return ip_finish_output2(skb);  

ip_queue_xmit 함수는 IP 레이어에서 필요한 작업을 한다. __sk_dst_check은 캐시(cache)한 route가 유효한지 확인한다. 캐시한 route가 없거나 유효하지 않으면 IP routing을 한다. 그리고 skb_push를 호출해서 IP 헤더 영역을 확보하고, IP 헤더 필드 값을 기록한다. 이후 함수 호출을 따라가면, ip_send_check가 IP 헤더 checksum을 계산하고, netfilter 함수도 호출한다. ip_finish_output 함수가 IP fragmentation이 필요하면 fragment를 만든다. TCP 사용시 fragmentation은 발생하지 않는다. 결국은 ip_finish_output2가 호출되고, 이것이 Ethernet 헤더를 추가한다. 이로써 패킷이 완성된다.

int dev_queue_xmit(struct sk_buff *skb)  
[...] ===>
static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, ...)  
[...]
if (...) {  
....
} else
if ((q->flags & TCQ_F_CAN_BYPASS) && !qdisc_qlen(q) &&  
qdisc_run_begin(q)) {  
[...]
if (sch_direct_xmit(skb, q, dev, txq, root_lock)) {  
[...] ===>
int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, ...)  
[...]
HARD_TX_LOCK(dev, txq, smp_processor_id());  
if (!netif_tx_queue_frozen_or_stopped(txq))  
ret = dev_hard_start_xmit(skb, dev, txq);

HARD_TX_UNLOCK(dev, txq);  
[...]
}

int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, ...)  
[...]
if (!list_empty(&ptype_all))  
dev_queue_xmit_nit(skb, dev);  
[...]
rc = ops->ndo_start_xmit(skb, dev);  
[...]
}

완성된 패킷은 dev_queue_xmit 함수를 통해 전송된다. 먼저 qdisc를 거친다. 기본 qdisc를 사용하고 큐가 비어있으면 sch_direct_xmit 함수를 호출해서 큐를 거치지 않고 패킷을 바로 드라이버로 내려 보낸다. dev_hard_start_xmit 함수가 실제 드라이버를 호출하는데, 드라이버를 호출하기 전에 디바이스 TX 락을 잡는다. 여러 스레드가 동시에 디바이스 접근하는 것을 막기 위해서다. 커널이 락을 잡기 때문에, 드라이버 전송 코드는 별도 락이 필요 없다. 다음 기회에 설명할 병렬 처리와 밀접한 관계가 있다.

ndo_start_xmit 함수가 드라이버 코드를 호출한다. 바로 전에, ptype_all, dev_queue_xmit_nit가 보인다. ptype_all은 패킷 캡쳐 같은 모듈을 포함하는 리스트다. 캡쳐 프로그램이 작동 중이면, 여기서 해당 프로그램으로 패킷을 복사한다. 따라서 tcpdump가 보여 주는 패킷은 드라이버로 전달되는 패킷이다. Checksum offload, TSO 등을 사용하면 NIC가 패킷을 조작하기 때문에, tcpdump 패킷은 실제 네트워크 선으로 전송되는 패킷과 다르다. 패킷 전송이 완료되면 드라이버 인터럽트 핸들러가 sk_buff를 반환한다.

코드 따라가기: 데이터 수신

둘째로 흔히 수행하는 경로는 패킷을 수신해서 receive socket buffer에 데이터를 추가하는 작업이다. 드라이버 인터럽트 핸들러 수행 후 napi poll 핸들부터 따라가 보자.

static void net_rx_action(struct softirq_action *h)  
{
struct softnet_data *sd = &__get_cpu_var(softnet_data);  
unsigned long time_limit = jiffies + 2;  
int budget = netdev_budget;  
void *have;

local_irq_disable();

while (!list_empty(&sd->poll_list)) {  
struct napi_struct *n;  
[...]
n = list_first_entry(&sd->poll_list, struct napi_struct,  
poll_list);  
if (test_bit(NAPI_STATE_SCHED, &n->state)) {  
work = n->poll(n, weight);  
trace_napi_poll(n);  
}
[...]
}

int netif_receive_skb(struct sk_buff *skb)  
[...] ===>
static int __netif_receive_skb(struct sk_buff *skb)  
{
struct packet_type *ptype, *pt_prev;  
[...]
__be16 type;  
[...]
list_for_each_entry_rcu(ptype, &ptype_all, list) {  
if (!ptype->dev || ptype->dev == skb->dev) {  
if (pt_prev)  
ret = deliver_skb(skb, pt_prev, orig_dev);  
pt_prev = ptype;  
}
}
[...]
type = skb->protocol;  
list_for_each_entry_rcu(ptype,  
&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
if (ptype->type == type &&  
(ptype->dev == null_or_dev || ptype->dev == skb->dev ||
ptype->dev == orig_dev)) {  
if (pt_prev)  
ret = deliver_skb(skb, pt_prev, orig_dev);  
pt_prev = ptype;  
}
}

if (pt_prev) {  
ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);

static struct packet_type ip_packet_type __read_mostly = {  
.type = cpu_to_be16(ETH_P_IP),
.func = ip_rcv,
[...]
};

앞서 설명했듯 net_rx_action 함수는 패킷을 수신하는 softirq 핸들러다. napi poll을 요청한 드라이버를 poll_list에서 가져와서 드라이버의 poll 핸들러를 호출한다. 드라이버는 수신한 패킷을 sk_buff로 포장하고, netif_receive_skb를 호출한다.

netif_receive_skb는 모든 패킷을 원하는 모듈이 있으면 그 모듈로 패킷을 전달한다. 패킷 전송 때와 같이 ptype_all 리스트에 등록된 모듈로 패킷을 전달한다. 패킷 캡처 작업은 여기서 수행된다.

그리고 패킷 종류에 따라 상위 레이어를 찾아 패킷을 전달한다. Ethernet 패킷은 헤더에 2 바이트 ethertype 필드를 포함한다. 이 값이 패킷 종류를 나타낸다. 이 값은 드라이버가 sk_buff에 기록한다(skb->protocol). 각 프로토콜은 자신만의 packet_type 구조체를 가지고, ptype_base hash table에 이 구조체의 포인터를 등록한다. IPv4는 ip_packet_type을 사용한다. Type 필드 값이 IPv4 ethertype (ETH_P_IP) 값이다. 따라서 IPv4 패킷은 ip_rcv 함수를 호출한다.

int ip_rcv(struct sk_buff *skb, struct net_device *dev, ...)  
{
struct iphdr *iph;  
u32 len;  
[...]
iph = ip_hdr(skb);  
[...]
if (iph->ihl < 5 || iph->version != 4)  
goto inhdr_error;

if (!pskb_may_pull(skb, iph->ihl*4))  
goto inhdr_error;

iph = ip_hdr(skb);

if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))  
goto inhdr_error;

len = ntohs(iph->tot_len);  
if (skb->len < len) {  
IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INTRUNCATEDPKTS);  
goto drop;  
} else if (len < (iph->ihl*4))
goto inhdr_error;  
[...]
return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, dev, NULL,  
ip_rcv_finish);  
[...] ===>
int ip_local_deliver(struct sk_buff *skb)  
[...]
if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {  
if (ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER))  
return 0;  
}

return NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN, skb, skb->dev, NULL,  
ip_local_deliver_finish);  
[...] ===>


static int ip_local_deliver_finish(struct sk_buff *skb)  
[...]
__skb_pull(skb, ip_hdrlen(skb));  
[...]
int protocol = ip_hdr(skb)->protocol;  
int hash, raw;  
const struct net_protocol *ipprot;  
[...]
hash = protocol & (MAX_INET_PROTOS - 1);  
ipprot = rcu_dereference(inet_protos[hash]);  
if (ipprot != NULL) {  
[...]
ret = ipprot->handler(skb);  
[...] ===>

static const struct net_protocol tcp_protocol = {  
.handler = tcp_v4_rcv,
[...]
};

ip_rcv 함수는 IP 레이어에서 필요한 일을 한다. 길이, 헤더 checksum 등 패킷 검사를 한다. netfilter 코드를 거치면 ip_local_deliver 함수를 수행한다. 여기서 필요하면 IP fragment들을 조립한다. 그리고 다시 netfilter 코드를 통해서 ip_local_deliver_finish를 호출한다. 이 함수는 __skb_pull을 사용해서 IP 헤더를 제거하고, IP 헤더의 protocol 값과 일치하는 상위 프로토콜을 찾는다. Ptype_base와 유사하게 각 트랜스포트 프로토콜은 inet_protos에 자신의 net_protocol 구조체를 등록한다. IPv4 TCP는 tcp_protocol을 사용하고, handler로 등록한 tcp_v4_rcv를 호출한다.

TCP 레이어로 들어오면 TCP 상태, 패킷 종류에 따라 패킷 처리 흐름이 다양하다. 여기서는 TCP 연결이 ESTABLISHED 상태에서 다음 예상하는 데이터 패킷을 받았을 때 처리 과정을 알아본다. 패킷 유실, 역전 현상이 없으면 데이터를 받는 서버가 자주 수행하는 경로다.

int tcp_v4_rcv(struct sk_buff *skb)  
{
const struct iphdr *iph;  
struct tcphdr *th;  
struct sock *sk;  
[...]
th = tcp_hdr(skb);

if (th->doff < sizeof(struct tcphdr) / 4)  
goto bad_packet;  
if (!pskb_may_pull(skb, th->doff * 4))  
goto discard_it;  
[...]
th = tcp_hdr(skb);  
iph = ip_hdr(skb);  
TCP_SKB_CB(skb)->seq = ntohl(th->seq);  
TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +  
skb->len - th->doff * 4);  
TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);  
TCP_SKB_CB(skb)->when = 0;  
TCP_SKB_CB(skb)->flags = iph->tos;  
TCP_SKB_CB(skb)->sacked = 0;

sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);  
[...]
ret = tcp_v4_do_rcv(sk, skb);  

우선 tcp_v4_rcv 함수는 받은 패킷이 올바른지 검사한다. 예를 들어, 헤더 크기가 데이터 오프셋보다 크면(th->doff < sizeof(struct tcphdr) / 4) 헤더 오류이다. 그리고 __inet_lookup_skb를 호출해서 TCP 연결 해시 테이블에서 패킷이 속하는 연결을 찾는다. 찾은 sock 구조체로부터 tcp_sock, socket 등 모든 필요한 구조체를 가져올 수 있다.

int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)  
[...]
if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */  
sock_rps_save_rxhash(sk, skb->rxhash);  
if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {  
[...] ===>
int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,  
[...]
/*
* Header prediction.
*/
if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags &&  
TCP_SKB_CB(skb)->seq == tp->rcv_nxt &&  
!after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt))) {
[...]
if ((int)skb->truesize > sk->sk_forward_alloc)  
goto step5;

NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPHPHITS);

/* Bulk data transfer: receiver */
__skb_pull(skb, tcp_header_len);  
__skb_queue_tail(&sk->sk_receive_queue, skb);  
skb_set_owner_r(skb, sk);  
tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;  
[...]
if (!copied_early || tp->rcv_nxt != tp->rcv_wup)  
__tcp_ack_snd_check(sk, 0);  
[...]
step5:  
if (th->ack && tcp_ack(sk, skb, FLAG_SLOWPATH) < 0)  
goto discard;

tcp_rcv_rtt_measure_ts(sk, skb);

/* Process urgent data. */
tcp_urg(sk, skb, th);

/* step 7: process the segment text */
tcp_data_queue(sk, skb);

tcp_data_snd_check(sk);  
tcp_ack_snd_check(sk);  
return 0;  
[...]
}

tcp_v4_do_rcv 함수부터 실제 프로토콜을 수행한다. ESTABLISHED 상태는 tcp_rcv_esablished를 호출한다. ESTABLISHED 상태가 가장 흔하기 때문에 이 상태 처리를 별도로 떼어 내서 최적화한다. tcp_rcv_established는 header prediction 코드를 먼저 수행한다. Header prediction도 흔한 경우를 감지해서 빨리 처리한다. 여기서 흔한 경우는 보낼 데이터는 없고, 받은 데이터 패킷이 다음에 받아야 하는 패킷인 경우, 즉 시퀀스 번호가 수신 TCP가 기대하는 시퀀스 번호인 경우다. 데이터를 소켓 버퍼에 추가하고 ACK를 전송하면 끝이다.

좀 더 따라가 보면 truesize와 sk_forward_alloc을 비교하는 문장이 보인다. Receive socket buffer에 새로운 패킷 데이터를 추가할 여유 공간이 있는지 확인한다. 공간이 있으면 header prediction은 "hit" (prediction 성공)이다. __skb_pull를 호출해서 TCP 헤더를 제거하고, __skb_queue_tail을 호출해서 패킷을 receive socket buffer에 추가한다. 마지막으로, __tcp_ack_snd_check를 호출해서 ACK 전송이 필요하면 전송한다. 이것이 패킷 처리의 끝이다.

만약 여유 공간이 부족하면 느린 경로를 수행한다. tcp_data_queue 함수는 버퍼 공간을 새로 할당하고 데이터 패킷을 소켓 버퍼에 추가한다. 이때 가능하면 receive socket buffer 크기를 자동으로 증가한다. 빠른 경로와 다르게, tcp_data_snd_check를 호출해서 새로운 데이터 패킷을 전송할 수 있으면 전송하고, 끝으로 tcp_ack_snd_check 호출해서 ACK 전송이 필요하면 ACK 패킷을 생성해서 전송한다.

지금 따라가 본 두 경로가 수행하는 코드의 양은 많지 않다. 자주 발생하는 경우(common case)를 최적화한 덕분이다. 바꿔 말하면 예상하지 않은 경우(uncommon case)의 처리 과정은 눈에 띄게 느리다는 뜻도 된다. 패킷 역전(out-of-order delivery) 현상이 대표적인 예다.

드라이버와 NIC의 통신

드라이버와 NIC 사이의 통신은 스택 가장 밑단이고, 대개 신경 쓰지 않는다. 하지만 성능 문제를 해결하기 위해 NIC가 수행하는 일이 많아졌다. 기본적인 작동 방식을 이해하면 추가 기술을 이해하는 데 도움이 된다.

드라이버와 NIC는 비동기 방식으로 통신한다. 먼저 드라이버가 패킷 전송을 요청하고(호출), CPU는 응답을 기다리지 않고 다른 작업을 수행한다. 이후 NIC가 패킷을 전송하고 CPU에 이 사실을 알리면 드라이버가 전송된 패킷을 반환한다(결과 리턴). 수신도 이와 같이 비동기 방식으로 이루어진다. 먼저 드라이버가 수신 요청을 하고 CPU는 다른 작업을 수행한다(호출). 이후 NIC가 패킷을 받으면 CPU에 이 사실을 알리고, 드라이버가 받은 패킷을 처리한다(결과 리턴).

따라서 요청, 응답을 저장하는 장소가 필요하다. 대개 NIC는 링(ring) 구조체를 사용한다. 링은 일반 큐 구조체와 유사하다. 고정된 수의 엔트리를 가지고, 한 엔트리가 한 요청 혹은 응답 데이테를 저장한다. 이들 엔트리들을 차례대로 돌아가며 사용한다. 돌아가며 고정된 엔트리들을 재사용하기 때문에 흔히 링이란 이름을 사용한다.

다음 그림의 패킷 전송 과정을 따라가며 링을 어떻게 사용하는지 알아보자.

networkstack7

그림 7 드라이버-NIC 통신: 패킷 전송

드라이버가 상위 레이어로부터 패킷을 받고, NIC가 이해하는 전송 요청(send descriptor)을 생성한다. send descriptor에는 기본적으로 패킷 크기, 메모리 주소를 포함하도록 한다. NIC는 메모리에 접근할 때 필요한 물리적 주소가 필요하다, 따라서 드라이버가 패킷의 가상 주소를 물리적 주소로 변경한다. 그리고 send descriptor를 TX ring에 추가한다(1). TX ring이 전송 요청 링이다.

그리고 NIC에 새로운 요청이 있다고 알린다(2). 특정 NIC 메모리 주소에 드라이버가 직접 데이터를 쓴다. 이와 같이 CPU가 디바이스에 직접 데이터를 전송하는 방식을 PIO(Programmed I/O)라고 한다.

연락을 받은 NIC는 TX ring의 send descriptor를 호스트 메모리에서 가져온다(3). CPU의 개입 없이 디바이스가 직접 메모리에 접근하기 때문에, 이와 같은 접근을 DMA(Direct Memory Access)라고 부른다.

Send descriptor를 가져와서 패킷 주소와 크기를 판단하고, 실제 패킷을 호스트 메모리에서 가져온다(4). Checksum offload 방식을 사용하면 메모리에서 패킷 데이터를 가져올 때 checksum을 NIC가 계산하도록 한다. 따라서 오버헤드는 거의 발생하지 않는다.

NIC가 패킷을 전송하고(5), 패킷을 몇 개 전송했는지 호스트의 메모리에 기록한다(6). 그리고 인터럽트를 보낸다(7). 드라이버는 전송된 패킷 수를 읽어 와서 현재까지 전송된 패킷을 반환한다.

다음 그림에서는 패킷 수신 과정을 볼 수 있다.

networkstack8

그림 8 드라이버-NIC 통신: 패킷 수신

우선 드라이버가 패킷 수신용 호스트 메모리 버퍼를 할당하고, receive descriptor를 생성한다. receive descriptor는 기본으로 버퍼의 크기, 주소를 포함한다. send descriptor와 같이 DMA가 사용하는 물리적 주소를 descriptor에 저장한다. 그리고 RX ring에 descriptor를 추가한다(1). 결국 이것이 수신 요청이고, RX ring은 수신 요청 링이다.

드라이버가 PIO를 통해서 NIC에 새로운 descriptor가 있다고 알린다(2). NIC는 RX ring의 새로운 descriptor를 가져온다. 그리고 descriptor에 포함된 버퍼의 크기, 위치를 NIC 메모리에 보관한다(3).

이후 패킷이 도착하면(4), NIC는 호스트 메모리 버퍼로 패킷을 전송한다(5). Checksum offload 기능이 있다면 NIC가 이때 checksum을 계산한다. 도착한 패킷의 실제 크기와 checksum 결과, 그 외 다른 정보는 별도의 링(receive return ring)에 기록한다(6). Receive return ring은 수신 요청 처리 결과, 즉 응답을 저장하는 링이다. 그리고 NIC가 인터럽트를 보낸다(7). 드라이버는 receive return ring에서 패킷 정보를 가져와서 받은 패킷을 처리한다. 필요에 따라 새로운 메모리 버퍼를 할당하고 (1)~(2) 단계를 반복한다.

스택 튜닝이라고 하면 흔히 ring, interrupt 설정을 조절해야 한다고 이야기한다. TX ring이 크면 한 번에 많은 수의 전송 요청을 할 수 있다. RX ring이 크면 한 번에 많은 수의 수신을 할 수 있다. 패킷 송신, 수신 burst가 많은 워크로드에는 큰 링이 도움이 된다. 그리고 CPU가 인터럽트를 처리하는 오버헤드가 크기 때문에, 대개 NIC은 인터럽트 회수를 줄이기 위해 타이머를 사용한다. 패킷을 전송하고 수신할 때 매번 인터럽트를 보내지 않고 주기적으로 모아서 보낸다(interrupt coalescing).

스택 내부 버퍼와 제어 흐름(flow control)

스택 내부의 여러 단에서 flow control을 수행한다.

그림 9는 데이터를 전송할 때 사용하는 버퍼를 보여 준다. 우선, 애플리케이션이 데이터를 생성하고 send socket buffer에 추가한다. 공간이 없으면 시스템 콜이 실패하거나, 애플리케이션 스레드에 블로킹이 발생한다. 따라서 커널로 유입되는 애플리케이션 데이터의 속도는 socket buffer 크기 제한을 통해 제어하도록 한다.

networkstack9

그림 9 패킷 전송에 관계된 버퍼들

TCP가 패킷을 생성해서 드라이버로 보낼 때는 transmit queue(qdisc)를 통하도록 하고 있다. 기본적인 FIFO 큐 형태이고, 큐의 최대 길이는 ifconfig 명령어를 실행할 때 확인할 수 있는 txqueuelen의 값이다. 보통 수 천 패킷 정도이다.

드라이버와 NIC 사이에는 TX ring이 있다. 앞서 설명했듯, 전송 요청 큐로 보면 된다. 큐 공간이 없으면 전송 요청을 못하고 패킷은 transmit queue에 적체된다. 너무 많이 적체되면 패킷 드롭을 한다.

NIC는 내부 버퍼에 전송할 패킷을 저장한다. 이 버퍼에서 패킷이 빠져나가는 속도는 우선 물리적 속도에 영향을 받는다(예: 1 Gb/s NIC가 10 Gb/s 성능을 낼 수는 없다). 그리고 Ethernet flow control을 사용하면 수신 NIC 버퍼에 공간이 없을 때는 전송이 멈춘다.

커널이 전송하는 패킷 속도가 NIC가 전송하는 속도보다 빠르면, 우선 NIC 내부 버퍼에 패킷이 적체된다. 버퍼에 공간이 없으면 TX ring의 전송 요청 처리를 멈춘다. TX ring에 점점 많은 요청이 적체되고, 결국은 큐 공간이 없어진다. 드라이버는 전송 요청을 못하고 패킷은 transmit queue에 적체된다. 이와 같이 여러 버퍼를 통해 backpressure가 밑에서 위로 올라간다.

그림 10은 반대로 수신한 패킷이 거쳐가는 버퍼를 보여 준다. 패킷은 NIC 내부 수신 버퍼에 저장된다. Flow control 관점에서 보면 드라이버와 NIC 사이의 RX ring를 패킷 버퍼로 생각하면 된다. RX ring에 들어간 패킷은 드라이버가 꺼내서 상위 레이어로 보낸다. 서버 장비가 사용하는 NIC 드라이버는 기본으로 NAPI를 사용하기 때문에 드라이버와 상위 레이어 사이에 버퍼는 없다. 상위 레이어가 RX ring에서 직접 패킷을 가져간다고 생각하면 된다. 그리고 패킷의 페이로드 데이터는 receive socket buffer에 들어간다. 이후 애플리케이션이 socket buffer에서 데이터를 가져간다.

networkstack10

그림 10 패킷 수신에 관계된 버퍼들

NAPI를 지원하지 않는 드라이버는 backlog queue에 패킷을 넣고, 후에 NAPI 핸들러가 패킷을 꺼내간다. 따라서, backlog queue는 상위 레이어와 드라이버 사이 버퍼로 보면 된다.

커널의 패킷 처리 속도가 NIC로 유입되는 패킷 속도보다 느리면 RX ring 공간이 없어진다. 그리고 NIC 내부 버퍼 공간도 없어진다. Ethernet flow control을 사용하면 NIC가 송신 NIC에 송신 정지 요청을 보내거나 패킷 드롭을 한다.

TCP는 end-to-end flow control을 지원하기 때문에, receive socket buffer 공간 부족으로 인한 패킷 드롭은 없다. 하지만 UDP는 flow control을 지원하지 않기 때문에, 애플리케이션 속도가 느리면 socket buffer 공간 부족으로 패킷 드롭이 발생한다.

그림 9와 그림 10에서 드라이버가 사용하는 TX ring의 크기와 RX ring의 크기가 ethtool이 보여 주는 링의 크기다. 대개 throughput을 중요시하는 워크로드에는 링의 크기, socket buffer 크기를 늘리면 도움이 된다. 많은 패킷을 빠른 속도로 전송, 수신할 때 버퍼 공간 부족으로 인한 실패 확률이 줄어들기 때문이다.

끝으로

네트워크 프로그램, 성능 실험, 트러블슈팅에 도움이 될만한 것들만 설명하려 했는데 정리하고 보니 내용이 적지 않게 되었다. 네트워크 애플리케이션을 개발하거나 성능 모니터링을 할 때 도움이 되었으면 한다. TCP/IP 프로토콜 자체는 상당히 복잡하고 예외 케이스도 많다. 하지만 성능 이해와 현상 분석을 하기 위해 운영체제의 TCP/IP 관련 코드 한 줄 한 줄을 모두 이해하고 있을 필요는 없다. 큰 흐름만 알고 있어도 많은 도움이 된다.

장비 성능과 운영체제의 네트워크 스택 구현이 꾸준히 발전해서, 최신 서버는 10-20 Gb/s 정도의 TCP throughput은 무리 없이 달성하고 있다. TSO, LRO, RSS, GSO, GRO, UFO, XPS, IOAT, DDIO, TOE 등 alphabet soup 같이 성능 관련한 기술 종류들이 많아서 오히려 혼란스러울 정도이다.

다음 글에서는 성능관점에서 스택을 살펴보고, 이 기술들이 해결하려는 문제와 효과를 설명하겠다.

반응형
반응형

출처 : http://coffeenix.net/board_view.php?bd_code=36



제  목 : 유용한 find 명령어 예 모음
작성자 : 좋은진호(truefeel, http://coffeenix.net/ )
작성일 : 수시로 추가했음

아래는 제가 자주 쓰는 find 명령인데, 유용할 듯 해서.
지금까지 적어뒀던 것과 아주 보편적이라고 생각되는 것입니다.
계속 추가됩니다. ^^

-------------------------------------------------------
1. 현재 디렉토리( . ) 이하에 확장자가 .html( -name "*.html" ) 인 파일만 ( -type -f )

find . -name "*.html" -type f -ls

2. 파일 크기

# 파일 크기가 300KB 이상( -size +300k )인 파일만 
# (호스팅되는 홈피내에 큰 사이트의 파일이 있는지 찾을 때 유용)
find . -size +300k -ls

# 파일 크기가 500bytes 이하( -size -500c )인 파일만  
find . -size -500c -ls 

3. 수정일

# 수정한지 20일 이상( -mtime +20 )된 파일과 디렉토리
find . -mtime +20 -ls 

# 수정한지 20일 이상된 파일만
find . -mtime +20 -type f -ls

# 수정한지 20일 이상된 파일만 삭제 ( -exec rm {} \; ) 
# (정기적으로 20일이 지난 파일을 삭제할 때 유용)
find . -mtime +20 -type f -ls -exec rm {} \;

# 수정한지 3일 이내( -mtime -3 )의 파일만 (백업할 때 유용)
find . -mtime -3 -type f -ls

# 수정한지 30분 이내( -mmin -30 )의 파일만
find . -mmin -30 -type f -ls

4. 퍼미션 및 파일 소유

# 파일시스템 전체( / )에서 SUID/SGID가 설정된 모든 파일 목록을 얻음
find / -type f \( -perm -04000 -o -perm -02000 \) -ls

# 소유자가 없는 파일 목록을 얻음 (사용자는 이미 삭제했는데, 파일이 남은 경우)
find / -nouser -o -nogroup

5. 출력 형식 지정

# 출력 형식을 printf로 만들어서 (출력 결과를 다른 프로그램에서 받아서 쓸 때 유용)
# %h = 경로, %f = 파일명, %k = KB, %s = Bytes

# 형식 : <경로/파일명> <파일크기KB>
find . -printf "%h/%f \t %kKB \n"
... 생략 ...
./public_html/phps/icon/type/pcx.gif      4KB
./public_html/phps/icon/type/ra.gif       4KB
./public_html/phps/icon/type/sound.gif    4KB
./public_html/phps/icon/type/text.gif     4KB

# 형식 : <경로/파일명> <파일크기Bytes>
find . -printf "%h/%f \t %sKB \n"
... 생략 ...
./public_html/phps/icon/type/movie.gif    912Bytes
./public_html/phps/icon/type/mp3.gif      958Bytes
./public_html/phps/icon/type/pcx.gif      897Bytes
./public_html/phps/icon/type/ra.gif       903Bytes
./public_html/phps/icon/type/sound.gif    932Bytes

6. 홈페이지 포팅할 때 퍼미션 안 맞는 경우 유용한 것

# 확장자가 .htm* .gif, .js, .css 인 것만 퍼미션을 644(rw-r--r--)로
find . -name "*.htm*" -o -name "*.gif" -o -name "*.js" -o -name "*.css" -exec chmod 644 {} \;

# 파일은 퍼미션을 644로
find . -type f -exec chmod 644 {} \;

# 디렉토리는 퍼미션을 701로
find . -type d -exec chmod 701 {} \;

# 하위의 모든 퍼미션을 바꾸지 않고 depth를 지정하여 제한을 둘 때
# 옵션 : -maxdepth 숫자  (1=현재디렉토리만, 2=현재디렉토리 포함하여 한단계 하위디렉토리까지만)
find . -maxdepth 1 -type d -exec chmod 701 {} \;

※ -maxdepth는 -type나 -perm 등의 조건연산자가 아닌 옵션이다. 
   따라서 조건연산자보다 먼저 사용해야한다. (다른 명령처럼 옵션을 먼저쓰는 것으로 이해하면 됨)
   find . -type -d -maxdepth 1 과 같이 사용하는 것은 옳지 않다.


반응형
반응형

Using static and shared libraries across platforms

I produced hereafter some information about shared libraries on different systems. However, this information is probably very sparse on details and may even not be up-to-date. Actually, keeping track of changes is nearly impossible.
The definitive information usually comes from the operating system docs. (e.g. HP's "HP-UX Linker and Libraries User's Guide", Sun's "Linker and Libraries Guide", SGI's "MIPSpro Compiling and Performance Tuning Guide", IBM's "AIX Linking and Loading Mechanisms", etc.), where there is often advice on the best options for performance.
GNU libtool offers an abstraction layer to shared library management.


Feedback is welcome.


Adapted from:
Cross platform development, Using Shared Libraries across Platforms, Shah, Amal ; Xiao, Hong, C/C++ Users JournalMay 1998, Volume 16 Number 5

Shared and static libraries information
LinuxSolarisHP-UXCompaq (Digital) Tru64AIXSGIWin32MacOS XVMSOS/390
Version[kernel 2.x, GCC 2.95.x and later][2.8][11][4.x][4.3 and later][Irix 6.5][NT 4][10.x][unmaintained][unmaintained]
1compiler flag (position independent code)-fPIC-KPIC, -Kpic+z/+Zxxxxxxxx-KPIC (default)xxxx-fno-commonxxxx-DLL
2ashared library creation flag-shared-G-b-shared-bM:SRE-sharedlink /DLLcc -bundle, -dynamiclib
libtool -dynamic
/SHARExxxx
2bshared library creation (C++)g++ -fPIC -shared -oCC -G -oaCC -b -ocxx -shared -oxlC -G (or -qmkshrobj)
obsolete:/usr/vacpp/bin/makeC++SharedLib -G -o
(was in /usr/ibmcxx/bin or/usr/lpp/xlC/bin/)
CC -shared -oCL -LD -Fexxx.DLL??
libtool -dynamic
????
2cstatic archiver (C++)arCC -xar -oarararCC -ar -oLIB (avoid link /lib that creates __impl symbols)??
libtool -static
????
3alibrary name(ld option) -soname name-h name(ld option) +h name(ld option) -soname namexxxx(ld option) -soname name/OUT:name-compatibility_version, -current_version/SHARE=xxxx
3bfile extension.so.so.sl.so.so (or .a).so.DLL.dylib.EXE??
4executable link options-Bdynamic
-Lpath -lname
-Bdynamic
-Lpath -lname
-a,shared
-Lpath -name
-no_archive
-Lpath -lname
-brtl
-bdynamic
-Lpath -lname
-Bdynamic,
-Lpath -lname
Controlled by .lib files??xxxxfilename/SHAREABLE
5aruntime path specification-rpath <path>-R <pathlist>-Wl,+b <pathlist> -Wl,+s-rpath <path>-blibpath:<path>
(by default, it is set to the arguments of -L)
-rpath <path>/LIBPATH:-install_name <path>xxxxxxxx
5bDoes not build the path for shared libraries into the executabledefault-norunpathchatr +b disable <file>default-blibpath:/usr/lib:/libdefault????????
6controlling symbolsusing a script file (see "info ld")-z defs/ nodefs/ muldefs+v[no] shlibunsats-expect [error] _unresolvedxxxx-ignore[no] _unresolved/FORCE: MULTIPLE [UNRESOLVED]??xxxxxxxx
LinuxSolarisHP-UXCompaq (Digital) Tru64AIXSGIWin32MacOS XVMSOS/390
7exports file/link option
(see notes)
using a script file (see "info ld")using a script file (see "man ld")+e,symname-exported_symbol.exp-exported_symbol
-exports_file filename
.def/__declspec(dllexport)-exported_symbols_list/SYMBOL_TABLE=(...).x file/
#pragma export()
8hiding symbolsusing a script file: VERSION command (see "Version Script" section in "info ld")using a script file (see "man ld") (see this article)-h symname-hidden_symbol, -hiddenxxxx-hidden_symbol,
-hiddens_file filename
using a .def file-unexported_symbols_listxxxxxxxx
9runtime library pathLD_LIBRARY_PATHLD_LIBRARY_PATH
LD_LIBRARY_PATH_64
SHLIB_PATH
LD_LIBRARY_PATH (64 bits)
LD_LIBRARY_PATHLIBPATHLD_LIBRARY_PATH
LD_LIBRARYN32_PATH
LD_LIBRARY64_PATH
. and then PATHDYLD_LIBRARY_PATH
DYLD_FALLBACK_LIBRARY_PATH
SYS$SHARELIBPATH
10symbol binding-Bsymbolic-Bsymbolic-Bsymbolic /immediate /deferredxxxxxxxx-Bsymbolicxxxx??xxxxxxxx
11runtime debugging(c.f. man ld.so)
LD_BIND_NOW
LD_TRACE_LOADED_OBJECTS
LD_DEBUG=help
ltrace
(c.f. man ld.so.1)
LD_BIND_NOW
LD_DEBUG
ld -D help
(c.f. man dld.sl)
_HP_DLDOPTS
(c.f. man loader)
LD_BIND_NOW
_RLD_ARGS
LDR_CNTRL(c.f. man rld)
LD_BIND_NOW
_RLD_PATH, _RLD_ARGS
xxxxDYLD_BIND_AT_LAUNCH
DYLD_PRINT_LIBRARIES
DYLD_PREBIND_DEBUG
xxxxxxxx
12runtime preloadLD_PRELOADLD_PRELOADLD_PRELOAD (probably HP-UX >= 11)_RLD_LIST "xxx.so:DEFAULT"xxxx_RLD_LIST "xxx.so:DEFAULT"??DYLD_INSERT_LIBRARIES????
13loaderld.sold.sodld.slloaderxxxxrldxxxxdyldxxxxxxxx
14runtime performancexxxxxxxxfastbind tool-quickstart_infoxxxx-quickstart_info/DELAYLOADxxxxxxxxxxxx
LinuxSolarisHP-UXCompaq (Digital) Tru64AIXSGIWin32MacOS XVMSOS/390
15versioningusing a script file: VERSION command (see "info ld")using a script file (see "man ld")
-M mapfile
xxxxxxxxxxxx-set_version/-exact_version/
-ignore_version
/VERSION:major.minor??/GSMATCH=xxxx
16entry pointsxxxxxxxxxxxxxxxxxxxxxxxxDllMainxxxxxxxxxxxx
17dynamic loading /
dynamic symbol access
dlopen / dlsymdlopen / dlsymshl_load / shl_findsym
(64 bits) dlopen / dlsym
dlopen / dlsymloadquery/loadbind
(AIX 4.2) dlopen / dlsym
dlopen / dlsymLoadLibrary / GetProcAddress"man 3 dyld"lib$find_image_symboldllload / dllqueryfn/ dllqueryvar
18utilitiesldd, ldconfig, objdump, ltrace, readelfldd, elfdump, pvs, dumpstabs (compilers V.6), crle (Solaris>=8)chatr
odump
ldd, elfdump (HP-UX >= 11)
odump -Dldump -H
ldd (in AIX tools)
elfdump -Dl
pldd
ldd (IRIX >= 6.5)
DUMPBIN, depends, EXEHDR, link -dumpotoolANALYSE/IMAGExxxx
19documentationman: ld, ld.so, ldd
info: ld, gcc, binutil
HOWTO: ELF-HOWTO, GCC-HOWTO
man: ld, ld.so.1, ldd, pvsman: ld, dld.sl, chatrman: ld, loader, odumpman: ld, dumpman: dso, ld, rld, elfdump, lddMSDNman: ld, libtool, dyld, otool????
LinuxSolarisHP-UXCompaq (Digital) Tru64AIXSGIWin32MacOS XVMSOS/390

Notes:


Acknowledgments

Juan Altmayer Pizzorno, Wolfgang Haefelinger, Per Losenborg, Anil E. Sahukar, Andrew Stalewski, Pirasenna Velandai Thiyagarajan, Nathan Stratton Treadway, Stephan Weber, Bo Xie

반응형
반응형

UNIX 및 Linux 운영 체제에서 ulimit 값 설정

UNIX 또는 Linux 운영 체제에서 적절한 ulimit 값을 설정하면 IBM® Cognos® Business Intelligence가 수행하는 방식에 영향을 미칠 수 있습니다.

예를 들어, Linux 운영 체제에서는 스택 ulimit 설정이 원인이 되어 발생하는 문제점에는 대형 보고서를 처리할 때 BIBusTKServerMain의 비정상적으로 높은 메모리 사용량 또는 BIBusTKServerMain 오류가 포함됩니다.

  • Linux 운영 체제에서 32비트 보고서 서비스를 사용 중인 경우 보고서는 실패할 수 있습니다.
  • Linux 운영 체제에서 64비트 보고서 서비스를 사용 중인 경우 실행 중인 보고서 또는 유휴 BIBusTKServerMain 프로세스가 사용 가능한 모든 RAM을 사용할 수 있습니다.

반면 UNIX 운영 체제에서는 스택 ulimit 설정이 너무 낮은 경우에 문제가 발생할 수 있습니다.

스택 ulimit 설정을 올바르게 설정하면 이러한 문제점을 방지할 수 있습니다.

새 설치에 권장되는 ulimit 설정은 다음과 같습니다.

IBM AIX®
  • CPU 시간(초): ulimit -t unlimited
  • 파일 크기(블록): ulimit -f unlimited
  • 최대 메모리 크기(KB): ulimit -m unlimited
  • 최대 사용자 프로세스: ulimit -u unlimited
  • 열린 파일 수: ulimit -n 8192(최소값)
  • 스택 크기(KB): ulimit -s 8192(최소값)
  • 가상 메모리(KB): ulimit -v unlimited
Sun Solaris
  • CPU 시간(초): ulimit -t unlimited
  • 파일 크기(블록): ulimit -f unlimited
  • 최대 사용자 프로세스: ulimit -u unlimited
  • 메모리(KB): ulimit -m unlimited
  • 열린 파일 수: ulimit -n 8192(최소값)
  • 스택 크기(KB): ulimit -s 8192(최소값)
  • 가상 메모리(KB): ulimit -v unlimited
HP-UX
  • CPU 시간(초): ulimit -t unlimited
  • 파일 크기(블록): ulimit -f unlimited
  • 메모리(KB): ulimit -m unlimited
  • 파일 수(디스크립터): ulimit -n 8192(최소값)
  • 스택 크기(KB): ulimit -s 8192(최소값)
Linux(x 및 z)
  • CPU 시간(초): ulimit -t unlimited
  • 파일 크기(블록): ulimit -f unlimited
  • 최대 메모리 크기(KB): ulimit -m unlimited
  • 최대 사용자 프로세스: ulimit -u unlimited
  • 열린 파일 수: ulimit -n 8192(최소값)
  • 스택 크기(KB): ulimit -s unlimited
  • 가상 메모리(KB): ulimit -v unlimited
참고: 애플리케이션의 수명 주기 동안 이러한 설정을 환경에 맞게 조정해야 할 수 있습니다.


반응형
반응형

[출처] 윈도우 서버를 NTP서버로 활용하는 방법|작성자 중고엑박


외부망이 연결되어 있는 경우는 큰 문제가 없겠지만...

내부망에 있는 PC들의 시간을 동기화시키는 경우에는 문제가 있습니다.


그런 경우 하나의 PC를 NTP서버로 지정하고 다른 PC를 그 PC의 시간으로 동기화 시켜주는 방법이 있는데요.

윈도우에는 내부적으로 w32time이라는 서비스를 NTP서버로 활용을 할 수 있습니다.

구글링을 해보다 Windows Server 2008 R2이상에서 사용할 수 있는 방법을 찾아서, 정리해 놓습니다.


(대부분의 자료들은 그 전버전 용이라 제대로 안되더군요.)

1. 다음의 레지스트리를 수정

HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/W32Time/Config에서

AnnounceFlags값을 5로 수정

HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/W32Time/TimeProviders/NtpServer에서

Enabled값을 1로 수정

2. Windows Time Service 재시작(제어판 -> 관리도구 -> 서비스 가서 재시작해도 되고, 다음과 같은 명령어로 재시작 가능)

net stop w32time && net start w32time


출처 : http://web-dev.tistory.com/656

AIX에서 시간 동기화 하기

 

1. TZ 설정(직접 설정)
    AIX 6.1 이상
    > smitty chtz_user
    AIX 6.1 미만
    > smitty chtz

2. 세부 설정
   # smitty chtz_date (1번 항목의 내용도 포함됨)
   Change Time Zone Using User Inputted Values

   Standard Time ID(only alphabets) : KORST
   Standard Time Offset from CUT : -9

3. 리부팅
   # rebooting

4. 시간 동기화
   # setclock time.bora.net
    - or (IP를 직접 입력) -
   # setclock  203.248.240.140



출처 : http://totoroaix.tistory.com/3

---현재시간 확인 ----
 root@node2:[/]#>date
 Wed Nov  7 13:12:18 KORST 2007
 root@node2:[/]#>date 11070101           (임의의 시간으로 변경)
 Wed Nov  7 01:01:25 KORST 2007
 root@node2:[/]#>

<시간을 동기화 합니다. DNS가 설정되어 있지 않다면 IP를 넣으셔도 무방합니다>    
   (time.nuri.net의 IP 211.115.194.21)
  root@node2:[/]#>ntpdate -u 211.115.194.21  
  7 Nov 23:05:13 ntpdate[8573]: step time server 211.115.194.21 offset -531.701132 sec
  root@node2:[/]#>date
  Wed Nov  7 23:05:18 KORST 2007

----동기화 완료!----

*  NTP 프로토콜은 Default로 UDP port 123를 사용합니다.만약 방화벽등에 의하여 포트가 막힌 경우에 다음과 같은 Error가 발생하는데 이런 경우 -u Option을 이용함으로써 다른 포트를 이용하게 할수 있습니다

   no server suitable for synchronization found
   
 root@node2:[/]#>ntpdate -u 211.115.194.21


*기타 NTP서버 리스트
우리나라에서 쓸만한 NTP 서버입니다.
ntp.ewha .net
zero.bora.net
ntp1.epidc.co.kr
ntp2. epidc.co.kr 
58.73.137.250 (kr.pool.ntp.org)
210.118.170.59 (kr.pool.ntp.org)

Stratum 1 을 써야 한다면
일본 후쿠오카에 있는 서 버를 쓰는게 좋은듯합니다.
clock.tl.fukuoka- u.ac.jp (133.100.11.8)
clock.nc.fukuoka-u.ac.jp (133.100.9.2)

-서버 리스트는 http://cafe.naver.com/fastlane/9에서 발췌하였습니다.

반응형
반응형

출처 : http://blog.naver.com/jwsanta?Redirect=Log&logNo=60009814755



INFODOC ID: 17468

개요: TCP Keepalive 해설
세부 설명:


Sun Microsystems는 TCP keepalive 매개 변수(tcp_keepalive_interval)를 15분 미만으로 설정하는 것은 바람직하지 않다고 봅니다.
이제 TCP keepalive를 설명한 후에, 왜 그것이 바람직하지 않은지 몇 가지 이유를 설명할 것입니다.

우선, keepalive가 TCP의 필수 요소가 아니라는 점을 말하고 싶습니다. keepalive는 TCP 규격에 나오는 옵션 기능의 하나이며, 제조업체의 재량에 따라 포함시킬 수 있습니다. Sun은 TCP에 이 기능을 포함시키기로 결정했습니다. 하지만 TCP 규격에서는 keepalive 기능을 포함시키는 경우 간격을 최소한 2시간 이상으로 기본 설정해야 한다고 규정합니다. 뿐만 아니라 이 기능을 옵션 기능으로 만들어야 합니다. 바로 그 점 때문에 TCP keepalive를 설정할 것인지 여부를 각 프로그램에게 맡기게 되는 것입니다.
프로그램이 TCP keepalive를 명시적으로 실행하지 않으면, 탐색 패킷(probe)을 보내지 않을 것입니다. TCP keepalive는 setsockopt()을 사용하여 소켓 옵션(SO_KEEPALIVE)을 설정하면 사용할 수 있게 됩니다.

소켓 옵션이 설정되면 tcp_keepalive_interval로 지정된 시간 동안 연결이 유휴 상태가 되었을 때 keepalive 탐색 패킷을 보냅니다.
응답 메시지가 수신될 때까지 또는 tcp_ip_abort_interval로 지정된 시간이 다 경과할 때까지 탐색 패킷을 보냅니다. 응답은 연결 상대측을 지연시키는 요소의 영향을 받습니다. 연결 상대측이 연결을 닫거나 다시 부팅을 하면 응답 메시지는 RST(reset packet)가 됩니다. 수신 주소에 도달할 수 없다는 ICMP 메시지를 수신하게 될 가능성도 있습니다. 라우터가 고장나거나 케이블 연결이 끊긴 경우에 그런 상황이 발생합니다. 그 외에도 많은 가능한 상황이 있습니다. 탐색 패킷 자체는 tcp_rexmit_interval로 지정된 간격으로 보내집니다.

keepalive를 15분 미만으로 설정해서는 안된다고 제안하는 이유 중의 하나는 바로 이것입니다. 그렇게 설정하면 TCP가 장애를 일으킬 가능성이 다분히 있습니다. tcp_rexmit_interval의 값은 3초로 기본 설정됩니다. 20초 정도로 높게 설정할 수도 있습니다. 그런데, tcp_keepalive_interval을 tcp_rexmit_interval 보다 작은 값으로 줄이면, 재전송하기 전에 keepalive 탐색 패킷을 보낼 것입니다. 하지만, 네트워크가 느리거나 팻 상태가 되면 재전송이 매우 중요합니다. 어쩌면 통신 상대측 시스템이 느려서 아직 응답하지 않은 것일 수도 있습니다. 재전송을 보내는 이유가 바로 이것입니다. 이것은 누군가에게 조금 전에 내가 한 말을 들었느냐고 묻는 것과 같습니다. 상대방이 없다고 판단되면 대화를 미리 중단하거나 상대방이 있는지 알아 보려고 시간을 낭비하게 될 것입니다. 상대측이 여전히 대화에 참여하고 있다면 그에게 직접 조금 전에 내가 한 말을 들었느냐고 다시 묻게 될 것입니다. 이렇게 되면 네트워크가 팻 상태가 됩니다. 네트워크가 팻 상태가 되면 될수록 제대로 작동이 되려면 재전송을 더 많이 해야 합니다. 그렇게 하여 TCP가 장애를 일으키게 됩니다.
(이제 tcp_rexmit_interval가 3개의 매개 변수, 즉 tcp_rexmit_interval_initial, tcp_rexmit_interval_max, 그리고 tcp_rexmit_interval_min로 나누어져 있다는 점을 지적해야겠습니다. 이 점에 대한 해설은 keepalive 해설에서 벗어난 것입니다. 여기서 사용하는 예에서는 주로 tcp_rexmit_interval_initial을 다룰 것입니다.)

텔넷의 경우에는 더 인상적입니다. 시스템에 텔넷 방식으로 연결되면 로그인을 하여 필요한 모든 작업을 할 수 있습니다. 하지만, 종종 작업을 멈추고 생각하는 시간도 있습니다. 그렇게 생각하는 동안 원격 호스트는 대기합니다. 그렇게 기다리는 동안에는 keepalive 탐색 패킷이 도착할 때까지 로컬 시스템과 원격 시스템 사이에 전송되는 패킷이 전혀 없습니다.
원격 호스트로 로그인한 다음에 10분 이상 생각에 잠기는 경우도 종종 있습니다. 그 10분 간격 동안 라우터가 다운이 되어 다시 부팅하게 되는 일도 쉽게 일어납니다. keepalive를 높은 값으로 설정하면 라우터 충돌을 느끼지 못하고 작업을 계속하게 될 것입니다.
하지만 1분 후에 keepalive 탐색 패킷를 보내면, 라우터는 다시 부팅할 시간이 없기 때문에 연결된 측이 준비가 되기 전에 연결이 닫히게 됩니다. 그러면 다시 로그인해야 합니다. 뿐만 아니라, 일단 연결이 닫히면 TIME_WAIT 상태로 유지된다는 점을 생각해야 합니다. TIME_WAIT 상태는 한쪽 호스트가 연결을 닫았는데, 늦게 도착한 패킷 때문에 다른 한 호스트에서는 연결을 계속 열어 두게 되는 상황을 방지하기 위해 사용합니다. 하지만, 이처럼 너무 일찍 연결을 종료시키면, 시스템에서 이용할 수 있는 모든 소켓이 닫히게 될 가능성이 있습니다. 그렇게 되면 전혀 연결이 되지 않을 것입니다. 이와 같은 시나리오에서는 15분이 훨씬 더 타당한 값입니다.

keepalive를 사용하는 주된 이유는 종단 시스템 중의 하나가 다운될 때 발생할 수 있는 한쪽만 열린 연결 상태를 정리하는 것입니다. 로컬 시스템이 대화를 하고 있는 원격 시스템이 다운이 되면, 로컬 시스템은 여전히 연결을 열어두고 있을 것입니다. 하지만, 다운된 그 시스템은 그렇지 않습니다. 이것을 한쪽만 열린 연결 상태라고 합니다. 네트워크 응용 프로그램이 시간 종료값이나 TCP keepalive 소켓 옵션을 설정하지 않는 한, 그 한쪽만 열린 연결 상태는 시스템이 다시 부팅할 때까지 그대로 유지됩니다. keepalive 탐색 패킷은 한쪽만 열린 연결 상태인지 확인하는데 사용되며, 한쪽만 열린 연결 상태이면 그 연결을 닫습니다.

이상의 내용은 몇 가지 상황에 대한 해설에 불과합니다. 분명히 사용자의 현재 상황에 훨씬 더 어울리는 시나리오가 더 많이 있을 것입니다. 기본적으로 여기서 말한 내용은 TCP 규격 자체가 keepalive의 기본 설정값이 최소한 두 시간이어야 한다고 규정한다는 점입니다. 더 나아가 Sun이 제안하는 요점은 TCP가 장애를 일으켜 네트워크를 팻 상태로 만드는 것을 방지하는 데 있습니다.
이것은 사용자가 수정하는 시스템과 네트워크의 다른 호스트에 그대로 적용됩니다. 문제의 네트워크에 전세계적인 인터넷이 포함되면 좀더 극적이 되는 것일 뿐입니다. 마지막 예에서는 keepalive를 다소 낮게 설정했을 때 발생하는 문제의 유형을 사용자 수준에서 설명합니다.

여기서 제안된 내용은 기술 지원과 개발 엔지니어링 분야에서 그리고 Sun Microsystems 전체에서 TCP를 다루는 작업을 하는 엔지니어들에게서 장기간에 걸쳐 보완된 것입니다.

TCP keepalive에 관하여 좀더 알고 싶다면 RFC 1122와 RFC 1123을 권합니다. Addison Wesley에서 발행한 책인 "TCP/IP Illustrated Volume I", ISBN: 0-201-63346-9의 필자인 Stevens도 멋지게 설명합니다.


제품 영역: Gen. Network
제품: TCP/IP
SUNOS 릴리즈: 해당 없음
하드웨어: 해당 없음


반응형
반응형



pthread 관련 함수 중

phtread_kill 함수는 특정 Thread에게 signal을 전송하는 기능을 수행하는 함수인데 관련 내용은 아래와 같다.


SYNTAX

int pthread_kill(pthread_t thread, int sig);

RETURN VALUE
성공 : 0
실패 : ERROR
ERRORS
ESRCH : thread ID로 해당 thread를 찾을 수 없는 경우
EINVAL : 잘못된 signal number를 전달할 경우



이 pthread_kill 함수를 코딩하여 멀티 플랫폼(Unix/Linux)에서 컴파일 하려고 할 때 

-lpthread 링크를 걸어야 하는 것 외에 추가적으로 명심해야 할 것이 있다.


그것은 바로 UNIX와 LINUX에서 오브젝트 파일을 컴파일 할 때 헤더파일 참조 위치가 다르다는 것인데

보통 코딩할 시 #include<pthread.h> 헤더파일 만을 추가 한 뒤 똑같은 코드를 

AIX, HP-UX(UNIX 계열), REDHAT,CENTOS(LINUX) 등에서 컴파일 하게 되면 재미 있는 현상을 경험 할 수 있다.


그것은 바로 LINUX에서 pthread_kill 함수를 찾을 수 없다는 내용.

error: 'pthread_kill' was not declared in this scope


AIX랑 HP-UX는 컴파일이 잘 되는데.. 

왜 리눅스 계열에서는 해당 에러가 발생하나 봤더니 그 이유는 /usr/include pthread.h 파일을 확인해 보면 알 수 있다.


유닉스 계열에서는 해당 함수가 /usr/include/pthread.h 또는 /usr/include/sys/pthread.h에 프로토 타입이 선언되어 있는 반면

리눅스는 찾을 수 없다..


이유는 리눅스에서는 해당 함수의 원형이 signal.h 파일에 포함되어 있기 때문이다.

시그널을 날리기 때문에 원형이 여기에 있는 것 같은데... 조금은 재미있는 배치다.

이것 때문에 삽질을... 얼마나 한겨..


끝.

반응형
반응형

출처 : Developing_C_C++_Application_on_AIX_AIX_DIY(SE)


64bit의 장점


 64bit로 개발하는 주요한 원인은 더 새롭고 빠른 64bit H/W1와 OS2의 성능을 이용할 수 있으며, 

복잡하고 메모리를 많이 이용하는 어플리케이션(데이터베이스, 과학계산 용 어플리케이션)에는 64bit가 유리하기 때문이다.

다음은 64bit환경에서 제공할 수 있는 장점이다.


- 64bit 어드레싱을 이용하므로 어플리케이션이 사용할 수 있는 주소공간은 4GB 이상이 된다.

- 가상주소공간이 커지므로 프로세스 데이터 공간도 커진다.

- 데이터 구조와 실행파일이 더 커진다.

- 표준 시스템 라이브러리 함수를 이용하여 더 큰 파일을 지원할 수 있다.

- 물리적 메모리양도 늘어나므로 시스템의 파일 캐시 크기도 늘어난다.

- 기계어 상에서 64bit 데이터를 사용할 수 있기 때문에 수학연산을 좀더 효과적으로 할 수 있으며 레지스터를 전체에 걸쳐 효과적으로 사용할수 있다.

- time_t, dev_t 등 시스템에서 사용하는 데이터 타입의 크기가 더 커진다.

- 메모리 공간이 커지므로 데이터를 디스크보다 메모리에 둘 수 있는 가능성이 높아져 I/O중심의 어플리케이션의 경우 성능이 급격히 개선될 수 있다.











반응형
반응형


이전 포스팅 : http://jangpd007.tistory.com/entry/Unix-Signal-%EC%A2%85%EB%A5%98


이전에 Signal의 전체적인 개념에 대해 잡았다면 이번에는 Signal 처리 방식에 대해 알아보자

Signal 처리 함수의 가장 기본적인 방식은 Siganl 함수를 이용해서 핸들러를 등록한 뒤 해당 Signal에 대해 Catch 된 이 후를 명시하는 방법이다.


Signal 함수의 기본 원형이다.

#include <signal.h>

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

Return 값 : 성공시 이전 Signal handler, 오류시 SIG_ERR


signal 함수의 두번째 인수로 주어진 값에 따라 수행여부가 결정되는데 입력 방식은 아래와 같다.

1. signal handler 함수 : 해당 Signal 을 catch 하여 handler 함수명을 지정

2. SIG_IGN : 해당 Signal은 무시(ignore)

3. SIG_DFL : 해당 Signal의 default action을 수행한다.

주의 사항은 SIGKILL(9), SIGSTOP(시스템에 따라 다름)는 시그널 핸들러를 사용자가 임의로 지정할 수 없으며 해당 Signal은 무시할 수도 없다. 

즉 signal 함수로 두가지 SIGNAL은 catch or ignore 할 수 없습니다. 

또한 해당 Signal들에 대해 핸들러를 등록할 때 컴파일 및 런타임 에러가 발생하지는 않습니다.

단지 기본동작(SIGKILL-Terminate, SIGSTOP-Stop Process)으로만 동작할 뿐입니다.

#include<signal.h>
#include<unistd.h>

void sig_handler_usr1(int signo)
{
   printf("catched sigusr1\n");
}
   
int main()
{
   if(signal(SIGUSR1, sig_handler_usr1) == SIG_ERR)
   {
      perror("SIGUSR1 ERROR");
   }
   while(1) sleep(1);
   return 1;
}




#include<signal.h>
#include<sys/types.h

int kill(pid_t pid, int sig);
int raise(int sig);
Return 값 : 성공시 0, 오류시 -1
함수 kill은 주어진 process에게 signal을 보낸다.
하지만 raise는 자신의 process에게 signal을 보낸다.




#include<unistd.h>

unsigned int alarm(unsigned int seconds);
Return 값 : 성공시 이전 alarm이 없을 경우 0, 있을 경우 이전 alarm의 남은 second 수
함수 alarm은 주어진 시간이 지난 후에 SIGALRM이 자신의 process에게 전달되게 한다.




#include<unistd.h>

int pause(void);
Return 값 : -1, errno은 EINTR.
함수pause는 signal이 deliver될 때 까지 sleep한다.





#include<stdlib.h>

void abort(void);
Return 값 : void
함수 abort는 자신의 process에게 SIGABRT을 보낸다.
process는 SIGABRT를 받으면 프로세스는 abnormal termination을 한다.




#include<unistd.h>

unsigned int sleep(unsigned int seconds);
Return 값 : 0 혹은 신호를 받은 경우 남은 sleep 시간(초)
함수 sleep은 주어진 시간(초) 동안 프로세스의 수행을 중단시킨다. 만약 sleep 도중 신호가 전달되면 sleep에서 깨어난다.



다음 포스팅은 신호 집합에 대해서 !!


반응형

'OS > Common' 카테고리의 다른 글

pthread_kill 를 사용하여 컴파일 시 유의사항  (2) 2014.01.24
64비트 컴파일 시 장점  (0) 2014.01.09
Unix/Linux Signal 개념 및 종류  (2) 2013.10.24
유닉스 언어 설정 확인 및 변경  (0) 2013.10.02
Z 확장자 압축해제  (0) 2013.07.09
반응형


UNIX 시스템의 핵심 중의 하나인 Signal은 프로세스에게 어떤 Event의 발생을 알리기 위해 전달 되는 소프트웨어 인터럽트다.

유닉스/리눅스 운영체제는 매우 다양한 종류의 Signal이 있으며 이러한 Signal은 각각의 의미를 가지고 사용되어진다.


이번엔 Signal의 종류 및 개념에 대해 간단히 알아보고 다음에 Signal 처리 방식에 대해 천천히 알아보자


우선 시그널의 정의 및 개념에 대해 알아보자.

1. Signal은 어떤 Event가 발생했음을 알리기 위해 Process에게 전달되는 소프트웨어 인터럽트다.

2. Signal을 발생 시키는 Event의 종류는 아래의 4가지 종류가 있다.

2-1. Hardware Exception (나누기 0 등).

2-2. Software condition (alarm 시간, expire 등).

2-3. 단말기에서 발생하는 사용자 입력 (^c, ^z 등).

2-4. kill 등과 같은 시스템 콜.

3. Event에 의해서 Signal이 생성 되면 곧 Process에게 전달 된다.

4. Process에게 Signal이 전달되면

4-1. 기본 설정 실행(ignore, terminate, terminate+core).

4-2. Signal Handler에 의한 Catch 후 로직 수행.

4-3. 무시.

5. Signal이 생성 되었으나 아직 전달 되지 않은 Signal은 Pending이라 함.

6. Process는 signal mask를 사용해 특정 Signal을 Block/Unblock 시킬 수 있음.

7. Process가 특정 Signal을 Block 시켜도 이 Signal은 생성되지만 전달 되지 않을뿐 Pending 됨.

8. Block된 Signal은 Process가 그 Signal을 Unblock 할 때까지 혹은 해당 Signal에 대한 처리를 ignore로 변경 할때 까지 Pending됨.

9. 어떤 Process에 여러개의 Signal이 생성되어 전달 되는 경우 순서는 보장할 수 없다.



주의 할 것은 UNIX/LINUX 시스템 마다 우리가 자주 사용하거나 보게 되는 기본적인 Signal을 제외하고 (SIGKILL(9), SIGSEGV(11), SIGTERM(15)  등등등) 기타 Signal 번호는 OS 환경에 설치된 signal.h에 define 선언 되어 있는 것 마다 차이가 있다.

각 Signal 번호는 어짜피 signal.h에 define 되어 있므로 궁금하면 /usr/include 에 있는 signal.h 파일을 참고하는 것이 좋다.

(Signal Number 정의는 UNIX /usr/include/sys/signal.h에서 확인하고 Linux는 /usr/include/bits/signum.h 참고)

혹은 직관적으로 확인하고자 한다면 프롬프트창에서 kill -l 을 치면 시스템 Signal 종류에 대해서 확인 할 수 있다.


기본적인 Signal과 은 아래와 같다. (시스템 마다 종류나 숫자는 차이가 있음)



1. SIGHUP: 연결된terminal이hangup하였을때(terminate)

2. SIGINT: interrupt key(^C)를입력하였을때(terminate)

3. SIGQUIT: quit key(^\)를입력하였을때(terminate+core)

4. SIGILL: illegal instruction을수행하였을때(terminate+core)

5. SIGTRAP: implementation defined hardware fault (terminate+core)

6. SIGABRT: abort시스템호출을불렀을때(terminate+core)

7. SIGBUS: implementation defined hardware fault (terminate+core)

8. SIGFPE: arithmetic exception, /0, floating-point overflow (terminate+core)

9. SIGKILL: process를kill하기위핚signal, catch 혹은ignore될수없는signal임(terminate)

10. SIGUSR1: user defined signal 1 (terminate)

11. SIGSEGV: invalid memory reference (terminate+core)

12. SIGUSR2: user defined signal 2 (terminate)

13. SIGPIPE: reader가terminate된pipe에write핚경우발생(terminate)

14. SIGALRM: alarm시스템호출후timer가expire된경우(terminate)

15. SIGTERM: kill시스템호출이보내는software termination signal (terminate)

16. SIGCHLD: child가stop or exit되었을때parent에게전달되는신호(ignore)

17. SIGCONT: continue a stopped process (continue/ignore)

18. SIGSTOP: sendable stop signal, cannot be caught or ignored (stop process)

19. SIGTSTP: stop key(^Z)를입력하였을때(stop process)

20. SIGTTIN: background process가control tty로부터read핛경우(stop process)

21. SIGTTOU: background process가control tty로write핛경우(stop process)

22. SIGURG: urgent condition on IO, socket의OOB data (ignore)

23. SIGXCPU: exceeded CPU time limit (terminate+core/ignore)

24. SIGXFSZ: exceeded file size limit (terminate+core/ignore)

25. SIGVTALRM: virtual time alarm, setitimer, (terminate)

26. SIGPROF: profiling time alarm, setitimer, (terminate)

27. SIGWINCH: terminal window size changed, (ignore)

28. SIGIO: 어떤fd에서asynchronous I/O event가발생하였을경우(terminate/ignore)

29. SIGPWR: system power fail (terminate/ignore)

30. SIGSYS: bad argument to system call (terminate+core)


기본적인 Signal 처리 방식은 아래와 같다.

1. SIG_DFL (SIG_PF)0
2. SIG_ERR (SIG_PF)-1
3. SIG_IGN (SIG_PF)1
4. SIG_HOLD (SIG_PF)2

Signal 처리에 관한 자세한 내용은 다음 포스팅 때!


반응형
반응형



유닉스 환경 상에서 언어 관련 정보는 locale 설정을 통해서 할 수 있다.

이 로케일에 대해서 검색하다가 다른 블로그에서 해당 내용을 확인할 수 있었는데 참고해야겠다.


참고 : http://blog.naver.com/paro01/100050474751



로케일(Locale)에 관하여...

 

로케일(Locale)의 의미

 

세계 여러 나라들은 각자 다른 문화(언어, 날짜, 시간 등)을 갖고 있다. 프로그램의 국제화(Internationalization,
줄여서 i18n)는 사용자로 하여금 프로그램 수행시 로케일이란 것에 의해 입맛에 맞는 환경을 선택할 수 있도록
만든 것을 말한다.  예를 들어 어떤 프로그램의 메시지가 여러가지 언어로 주어져 있는 경우 이중에 어떤 언어의
것을 출력할 것인가를 사용자가 결정할 수 있는 것이다. 그것을 가능하게 해 주는 수단이 바로 로케일이다.
이것은 단순히 메시지 뿐만이 아니고 숫자표현법, 날짜 또는 시간표현법 등 여러가지에 사용될 수 있다.
그것 각각을 우리는 카테고리(category)라고 부른다. 카테고리에는 LC_COLLATE, LC_CTYPE, LC_MESSAGES,
LC_MONETARY, LC_NUMERIC, LC_TIME 가 있다.

 

로케일 설정방법

 

로케일을 지원하는 프로그램의 실행 방식을 선택하기 위해서는 환경 변수 설정을 이용한다.
(카테고리 각각에 해당하는 환경변수는 카테고리 이름과 동일하다.)
로케일 환경 변수에 관한 정보는 locale이란 명령으로 간단히 얻을 수 있다.


% locale


LANG=ko_KR.eucKR
LC_CTYPE="ko_KR.eucKR"
LC_NUMERIC="ko_KR.eucKR"
LC_TIME="ko_KR.eucKR"
LC_COLLATE="ko_KR.eucKR"
LC_MONETARY="ko_KR.eucKR"
LC_MESSAGES="ko_KR.eucKR"
LC_ALL= 위에서 ko_KR.eucKR은 로케일 값(locale name)이다.

일반적인 로케일 값의 형식은 ll[_CC[.EEEE]][@dddd] 이다.
ll은 언어(language)를 지정하는 소문자 두 글자 ISO 639 language code,
CC는 지역(territory)를 지정하는 대문자 두 글자 ISO 3166 country code,
EEEE는 코드셋(codeset)을 지정하는 문자셋(character set) 또는 인코딩(encoding),
dddd는 방언 등의 변종을 구별하기 위한 것(modifier)이다.
[]로 표시된 내용은 안 쓸수도 있음을 의미한다.

예를 들면 en_US는 미국 영어권, en_CA는 영어권 카나다, de_DE는 독일의 독일어, fr_FR는 프랑스의 프랑스어를 의미한다.
아무 로케일도 설정하지 않았을 때 glibc에서의 기본 로케일은 C 또는 POSIX (glibc에서는 C 로케일의 alias) 로케일이다.

 

% locale -a

라는 명령을 이용하면 이외에 사용 가능한 로케일의 이름들을 알 수 있다.

 

 

다음은 여러가지 환경변수의 역할(카테고리의 경우에는 동시에 카테고리의 역할)에 관한 설명이다.

 

LANG : 모든 카테고리에 대한 로케일 설정을 위한 환경변수이다. 하지만 LC_* 환경변수보다 우선 순위가 낮다.
LC_ALL이 설정이 안 되어 있고 LC_* 값들이 설정이 따로 설정이 않된 경우 LANG을 변화시키면 LC_ALL을 제외한 로케일 카테고리들의
값이 변경되지만 LC_ALL이 설정 되어 있는 경우 LANG의 변화는 로케일 카테고리들의 값에 영향을 주지 않는다.

 

LC_CTYPE : 문자 분류(알파벳, 숫자, 한글 또는 소문자, 대문자 등등), 변환, 대소문자 비교을 위한 로케일 설정을 의미한다.
이것은 예를 들어 fgetwc(), is*(), isw*(), mblen(), mbtowc(), wcstombs() 등의 함수에 영향을 줄 수 있다.

 

LC_COLLATE : 스트링(string)의 정렬 순서(sort order 또는 collation)를 위한 로케일 설정을 위해 사용된다.
이것은 예를 들어 strcoll(), wcscoll(), strxfrm() 등의 함수에 영향을 줄 수 있다.

 

LC_MESSAGES : 메시지 표현을 위한 로케일 설정. 메시지의 국제화를 위한 catopen(), gettext() 등의 함수에 영향을 줄 수 있다.

LC_NUMERIC : 금액이 아닌 숫자 표현(천단위, 소수점, 숫자 그룹핑 등)을 위한 로케일 설정.
예를 들어 strtod(), atof().

 

LC_MONETARY : 금액 표현(천단위 구분 문자, 소수점 문자, 금액 표시 문자, 그 위치 등)을 위한 로케일 설정.
예를 들어 strfmon().

 

LC_TIME : 시간과 날짜의 표현(년, 월, 일에 대한 명칭 등)을 위한 로케일 설정
예를 들어 strftime(), strptime().

 

LC_ALL : 모든 카테고리에 대한 로케일 설정을 위한 환경변수이다.
위의 LC_* 및 LANG의 어떤 것보다 우선 순위가 높다. 그리고 LC_ALL을 설정하면 다른 로케일 카테고리의 값들이 LC_ALL의 값의 변경되고  LC_ALL설정을 없애면 다른 로케일 카테고리의 값들은 이전값을 유지한다.

 

LANGUAGE : 로케일의 다중 설정을 위해 gettext에서 사용되는 GNU extension  환경변수로 LC_ALL보다도 우선순위가 높다.
로케일들은 구분문자 : 을 이용하여 우선순위가 높은 순대로 나열된다.

예를 들어 LANGUAGE=en_US:ko_KR LINGUAS : gettext를 사용하는 프로그램 설치시 지정한 언어들의 메시지만을
설치하기 위한 환경변수. 구분 문자는 스페이스이다. 예를 들어 LINGUAS="ko ja"

로케일을 지원하기 위한 방법 및 작동 원리

 로케일을 제대로 지원하는 프로그램을 작성하기 위해서는 setlocale()함수를 이용하여 로케일을 설정하고 확인하여야 한다.
 setlocale()함수는 헤더 파일 locale.h 에 정의되어 있으며 그 프로토타입은 다음과 같다.


반응형
반응형

 

압축파일이다.

초기 유닉스 환경에서 사용되던 것인데 이번 Solaris studio 설치를 위해 jdk 설치를 하려 보니

jdk 압축이 .gz, Z 등으로 되어 있었다.

 

gz 이야 그렇다 치지만 Z는 뭔가 특이한건줄 알았더만 보통 압축파일 이었다... 허허허

기본적으로 압축과 압축해제는 아래와 같다.

 

compress [파일명]

uncompress [파일명]

 

하지만 기본적으로 gzip 으로 압축해제가 가능하다.

 

gzip -d [파일명]

gunzip [파일명]

 

 

 

 

반응형
반응형

굉장히 도움이 될 것 같아서 퍼옴..

출처 : http://cafe.daum.net/oddtip/Jxkw/94?docid=1CBe5Jxkw9420081218175643]

 

AIX, HP-UX, SOLARIS 특징 및 명령어 비교
     
Directory AIX HP-UX SOLARIS
Root filesystem / {/dev/hd4} / {/dev/vg00/lvol1} / {/dev/vx/dsk/rootvol}
Home Directory /home {/dev/hd1} /home {/dev/vg00/lvol4} /export/home
      /dev/vx/dsk/home}
  /tmp {/dev/hd3} /tmp {/dev/vg00/lvol6} /tmp
      /dev/vx/dsk/swapvol}
  /usr {/dev/hd2} /usr {/dev/vg00/lvol7} /usr
  /var {/dev/hd9var} /var {/dev/vg00/lvol8} /var
Sample configuration files - /usr/newconfig  
User Accounts AIX HP-UX Solaris
Password files /etc/passwd /etc/passwd /etc/passwd
  /etc/security/passwd /tcb/files/auth/r/root /etc/shadow
Groups file /etc/group /etc/group /etc/group
  /etc/security/group /etc/logingroup  
Maximum # of user ID 4294967295 2147483647 2147483647
Allow/Deny remote login /etc/security/user /etc/securetty /etc/default/login
  {rlogin=true} {console} {CONSOLE=/dev/console}
User nobody's id # 4294967294 -2 60001 & 65534(nobody4)
Group nobody's id # 4294967294 -2(nogroup) 60002 & 65534(nogroup)
Recover root password boot from CD/Tape ISL>hpux -is boot cdrom -s
  Installation/Maintenance vi /tcb/files/auth/r/root mount /dev/c0t0d0s0 /mnt
  Start Limited Shell vi /etc/shadow vi /mnt/etc/shadow
  getrootfs hdisk0    
  vi /etc/security/passwd    
Create new user mkuser useradd useradd
Delete user rmuser userdel userdel
List users lsuser -f ALL logins logins
Modify user account chuser -a usermod usermod
General Commands AIX HP-UX Solaris
Unique host ID hostid uname -i hostid
Administrator smit sam admintool
Performance monitor top top top
  monitor glance  
System activity reporter sar sar sar
Virtual Memory statistics vmstat vmstat vmstat
I/O statistics iostat iostat iostat
Error logs alog -o -t boot dmesg dmesg
  errpt    
Physical RAM 1M TB 4TB 16TB
Shared Memory 64K TB 8TB  
Process Data Space 384K TB 4TB  
Swap device /dev/hd6 /dev/vg00/lvol2 /dev/vx/dsk/swapvol
Swap file type /etc/swapspaces swap swap
Display swap size lsps -a swapinfo -a swap -l
Activate Swap swapon -a swapon -a swap -a
Printers AIX HP-UX Solaris
Printer Queues /etc/qconfig /etc/lp/interface/* /etc/lp/interfaces/*
Stop LP stopsrc -s lpd lpshut /usr/lib/lp/lpshut
Start LP startsrc -s lpd lpsched /usr/lib/lp/lpsched
Submit print jobs enq lp lp
  lp   lpr
  lpr    
  qprt    
LP statistics enq -A lpstat lpstat
  lpq    
  lpstat    
  qchk    
Remove print jobs cancel cancel cancel
  lprm   lprm
  qcan    
  enq -x    
Add printer queue smit mkpq lpadmin -p pq lpadmin -p pq
Remove Printer queue smit rmpq lpadmin -x pq lpadmin -x pq
Make default printer export LPDEST="pq" lpadmin -d pq lpadmin -d pq
TCP/IP AIX HP-UX Solaris
Network IP configuration lsattr -E -l inet0 /etc/rc.config.d/netconf /etc/hostname.*
      /etc/inet/*
      /etc/defaultrouter
Hosts IP addresses /etc/hosts /etc/hosts /etc/inet/hosts
Name service switch /etc/netsvc.conf /etc/nsswitch.conf /etc/nsswitch.conf
Network parameters no -a ndd -h ndd /dev/[tcp|ip]
Routing daemon gated gated in.routed
NIC Configurations ifconfig -a lanscan -v ifconfig -a
Secondary IP Address ifconfig en0 alias IP ifconfig lan0:1 IP ifconfig hme0:1 IP up
       
Login prompt HERALD @ telnetd -b /etc/issue BANNER @
  /etc/security/login.cfg   /etc/default/telnetd
Increase the # of pseudo-terminals odmget -q "attribute=num and uniquetype=pty/pty/pty" PdAt | sed "s/0-64/0-512/" | rebuild your kernel with these new values NPTY=# {/etc/system}
  odmchange -q "attribute=num and uniquetype=pty/pty/pty" -o PdAt NSTRPY=# set pt_cnt = # {SYSV}
      set npty = # {BSD}
  chdev -l pty0 -anum=256 -P reboot  
  reboot   {/etc/iu.ap}
    insf -d ptys -n # ptsl 0 # ldterm ttcompat
    insf -d ptym -n #  
    insf -d pts -s # -e -v halt
      boot -r
Maximum # of ptys 512 {MAXUSERS} 176 {BSD}
      3000 {SYSV}
Remote Shell remsh remsh rsh
  rsh    
YP/NIS service binder /usr/lib/netsvc/yp/ypbind /usr/lib/netsvc/yp/ypbind /usr/lib/netsvc/yp/ypbind
System Files AIX HP-UX Solaris
NFS exported /etc/exports /etc/exports /etc/dfs/dfstab
      /etc/dfs/sharetab
NFS Client mounted directories /etc/xtab /etc/xtab /etc/rmtab
Max File System 128 GB 128 GB 1 TB
Max File Size 64 GB 128 GB 1 TB
Max # File Descriptors 64 K 60~ K 64 K
DISK/LVM Commands AIX HP-UX:Disk &Filesystem SOLARIS
Filesystem table /etc/filesystems /etc/fstab /etc/vfstab
Free disk blocks df -k bdf df -k
Device listing lsdev -C /sbin/ioscan sysdef
Disk information bootinfo -s hdisk# diskinfo /dev/rdsk/c#t#d# format -d c#t#d#
      format>current
      format>inquiry
Disk Label lspv -l hdisk# pvdisplay -v /dev/dsk/C#t#d# prtvtoc
LVM Concepts Partition logical extents sub disk
  Volume logical volume Volume
      Plex
  Volume group volume group disk group
Journal Filesystem type jfs vxfs vxfs
Default volume group /dev/rootvg /dev/vg00 /dev/vx/dsk/rootdg
Display volume group lsvg -l rootvg vgdisplay -v vg00 vxprint -l -g rootdg
Modify physical volume chpv pvchange  
Prepare physical disk mkdev -c disk -l hdisk# pvcreate vxdiskadd
List physical volume lspv pvdisplay vxprint -dl
Remove disk from volume group reducevg vgreduce vxdg rmdisk
Move logical volumes to another physical volumes migratepv pvmove vxassist move
Create volume group mkvg vgcreate vxdg init
Remove volume group   vgremove  
Volume group availability chvg vgchange  
  varyonvg    
  varyoffvg    
Restore volume group   vgcfgrestore  
Exports volume group exportvg vgexport vxdg deport
Imports volume group importvg vgimport vxdg import
Volume group listing lsvg vgscan  
Change logical volume characteristics chlv lvchange vxedit set
List logical volume lslv lvdisplay vxprint -vl
Make logical volume mklv lvcreate vxassist make
Extend logical volume extendlv lvextend vxassist growto
Reduce logical volume AIX reduce LV lvreduce vxassist shrinkto
Remove logical volume rmlv lvremove vxedit rm
Prepare boot volumes bootlist -m normal lvlnboot vxbootsetup
Remove boot volumes   lvrmboot  
Extend File system chfs -a size=# extendfs -F vxfs -s # vxva
    fsadm -F vxfs -b {LE * 1024} mkfs -M
Reduce/Split mirrors rmlvcopy lvsplit  
Merge mirrors   lvmerge  
Create mirrors mklv -c 2 lvcreate -m 1 vxassist mirror
Add mirrors mklvcopy lv 2 lvextend -m 1  
Create striped volumes mklv -u 3 -S 64K lvcreate -i 3 -I 64 vxassist make vol 100mb layout=raid5
System recovery tape mksysb -i /dev/rmt0 /opt/ignite/bin/make_recovery  
Backup savevg -i rootvg fbackup ufsdump
Restore restvg frecover ufsrestore
MISC AIX HP-UX SOLARIS
Startup script /etc/rc /sbin/rc /sbin/init.d
Kernel /usr/lib/boot/unix_up /stand/vmunix /kernel/genunix
Kernel Parameters lsattr -E -l sys0 kmtune sysdef- i
    kmsystem  
Reconfigure the kernel   cd /stand/build vi /etc/system
  chdev -l sys0 -a /usr/lbin/sysadm/system_prep -v -s system reboot
    vi system  
    mk_kernel -s system  
    cd /stand  
Reconfigure the kernel   mv system system.prev  
    mv vmunix vmunix.prev  
    mv dlkm dlkm.prev  
    mv ./build/system system  
    kmupdate /stand/build  
       
List modules   kmadmin -s modinfo
Load module   kmadmin -L modload
Unload module   kmadmin -U modunload
Initialize system install_assist set_parms initial sys-unconfig
Physical RAM bootinfo -r grep -i Physical /var/adm/syslog/syslog.log prtconf
Kernel Bits getconf WORD_BIT getconf KERNEL_BITS isainfo -kv
Crash utility crash crashutil crash
Machine model uname -m model uname -imp
  bootinfo -m uname -m  
OS Level oslevel uname -r uname -r
Run Level who -r who -r who -r
Core dump files /var/adm/ras /var/adm/crash /var/crash/`uname -n`
Boot single user Key on service mode/F4 ISL>hpux -iS ok boot -s
  Boot from CD/Tape    
  Select Maintenance    
  Limited function Shell    
Maintenance mode   ISL>hpux -lm ok boot -as
Interrupt Key   control-B Stop-A
Return to console   co ok go
Software AIX HP-UX SOLARIS
Install Software installp -a swinstall pkgadd
Uninstall software installp -u swremove pkgrm
List installed software lslpp -L all swlist pkginfo
Verify installed software lppchk -v swlist -l fileset -a state pkginfo -i
      pkginfo -p
List all files lslpp -f fileset swlist -l file fileset pkgchk -l package
List installed patches instfix -i swlist -l patch patchadd -p
    what /stand/vmunix  
Package owner lslpp -w path swlist -l file | grep path pkgchk -l -p path
SW Directory /usr/lpp /var/adm/sw/ /var/sadm
Devices AIX HP-UX SOLARIS
Devices /dev /dev /devices
Install devices for attached peripherals cfgmgr -v insf -e drvconfig
      devlinks
      disks
      tapes
      ports
Remove device rmdev -l rmsf rem_drv
Device drivers lscfg lsdev prtconf -D
CPU lsdev -Cc processor ioscan -fnC processor psrinfo -v
List Terminal lsdev -Cc tty ioscan -fnC tty pmadm -l
Diagnostics diag stm /usr/platform/`uname -m`/
      sbin/prtdiag
      ok test-all
      /opt/SUNWvts/bin/sunvts
Whole Disk /dev/hdisk# /dev/dsk/c#t#d0 /dev/c#t#d0s2
CDROM /dev/cd0 /dev/dsk/c#t2d0 /dev/dsk/c#t6d0s2
CDROM file type cdrfs cdfs hsfs
Rewinding tape drive /dev/rmt0 /dev/rmt/0m /dev/rmt/0
Non-rewinding tape drive /dev/rmt0.1 /dev/rmt/0mn /dev/rmt/0n
Floppy drive /dev/rfd0 - /dev/diskette
Links AIX HP-UX SOLARIS
FAQ AIX-FAQ HP-UX FAQ Solaris 2 FAQ
Online Manual AIX 4.3 Books HP-UX 11.00 Collection Solaris 7 Documentation
Technical Support RS/6000 TechSupport IT Resource Center SunSolve
Phone Number 1-800-CALL-AIX 1-800-633-3600 1-800-USA-4SUN
Free Software Bull HP-UX Ports Sun Freeware
Certification www.ibm.com education.hp.com suned.sun.com

 

잘 알아놓고 두고두고 써야겠당

 

 

 

반응형

'OS > Common' 카테고리의 다른 글

유닉스 언어 설정 확인 및 변경  (0) 2013.10.02
Z 확장자 압축해제  (0) 2013.07.09
해당 바이너리의 비트 확인하기  (0) 2012.05.21
ftp 사용법 [명령어]  (0) 2011.10.20
Tar 와 Gzip Bzip2사용법  (0) 2011.10.20
반응형

 

-------------------------------------------------------

file [바이너리명]

: 몇 비트 파일인지 확인 할 수 있다.

 

-------------------------------------------------------

nm 사용법 -> 알아봅시다.

 

 

-------------------------------------------------------

- 해석되지 않은 심볼
현상 : ld: 0711-317 ERROR: Undefined symbol: .pow
ld: 0711-345 Use the -bloadmap or -bnoquiet option to obtain more information.
원인 : 심볼을 해석하지 못한 에러는 다양한 경우에 발생할 수 있지만 대부분의 이유는 필요한 파일을 제대로 주지 않은 경우이다.
조치 : 라이브러리에 들어있지 않은 라이브러리 함수를 호출하는 경우 해당하는 함수가 들어있는 라이브러리를 지정해주어야 한다.

- 동일한 심볼을 중복해서 정의할 경우 프로그래밍 에러가 발생.
현상 : ld: 0711-224 WARNING: Duplicate symbol:
.A<int>::f()
ld: 0711-345 Use the -bloadmap or -bnoquiet option to obtain more information.
원인 : 이 경우 링커는 첫번째 심볼 만을 인정하기 때문에 의도하지 않은 결과가 발생할 수 있다. 함수의 이름을 바꾸던가 정적(static) 함수를 사용해야 한다.
조치 : 심볼이 중복되어 똑같이 정의되어 있으므로 -bhalt:5 옵션을사용해서 링커에게 메시지를 보여주지 않도록 해야 한다.
-bhalt 링커 옵션은 링킹 과정 중 지정한 숫자보다 적은 에러메시지가 발생하면 이 메시지를 보여주지 않도록 한다.

- 링킹과정 중 메모리가 충분하지 않을 때
현상 : ld: 0711-101 fatal error, allocation of bytes fail in routine initsymtab_info.
There is not enough memory.
원인 : 대부분 원인은 페이징 공간이 너무 크기가 작거나, 링커명령을 사용한 사용자의 자원제한이 너무 낮아서 발생한다.
조치 : 위와 같은 에러가 발생하면 다음 사항을 체크해보고 가능하다면 페이징 공간을 늘리는 편이 좋다.
1.시스템 내의 가용한 페이징 공간
2.링커를 사용한 사용자가 사용할 수 있는 자원의 제한. 이 상황은 ulimit 명령으로 알아볼 수 있다.

-------------------------------------------------------

-lm

/bin/sh ./libtool --silent --tag=CC --mode=link gcc -g -O2 -Wall -W -D_THREAD_SAFE -o utilities/animate utilities/animate.o magick/libMagick.la wand/libWand.la
ld: 0711-317 ERROR: Undefined symbol: .fmod
ld: 0711-317 ERROR: Undefined symbol: .cos
ld: 0711-317 ERROR: Undefined symbol: .sin
ld: 0711-317 ERROR: Undefined symbol: .pow
ld: 0711-317 ERROR: Undefined symbol: .ceil
ld: 0711-317 ERROR: Undefined symbol: .sqrt
ld: 0711-317 ERROR: Undefined symbol: .cexp
ld: 0711-317 ERROR: Undefined symbol: .exp
ld: 0711-317 ERROR: Undefined symbol: .floor
ld: 0711-317 ERROR: Undefined symbol: .atan2
ld: 0711-317 ERROR: Undefined symbol: .hypot
ld: 0711-317 ERROR: Undefined symbol: .tan
ld: 0711-317 ERROR: Undefined symbol: .log
ld: 0711-317 ERROR: Undefined symbol: .log10
ld: 0711-317 ERROR: Undefined symbol: .acos
ld: 0711-317 ERROR: Undefined symbol: .asin
ld: 0711-317 ERROR: Undefined symbol: .atan
ld: 0711-345 Use the -bloadmap or -bnoquiet option to obtain more information.
collect2: ld returned 8 exit status
make: 1254-004 The error code from the last command is 1.

에러 제거시

You're obviously missing libm.so (or libm.a or libm.sl or whatever the
extension for (shared) libraries is on your system).

You can check config.sh to see if Configure includes -lm in the 'libs='
line

libs='-lbind -lnsl -ldbm -ldb -ldl -lld -lm -lcrypt -lc -lbsd';

if it does, check to see if libm.a is in any of the path's shown for
libs

libdirs=' /usr/local/ppc64/lib64  /lib /pro/local/lib';
libpth='/usr/local/ppc64/lib64 /lib /usr/lib /usr/ccs/lib /usr/local/lib';
libsdirs=' /lib /usr/local/ppc64/lib64';
libld.a /lib/libm.a /lib/libcrypt.a /lib/libc.a /lib/libbsd.a';
libspath=' /usr/local/ppc64/lib64 /lib /usr/lib /usr/ccs/lib /usr/local/lib';

-------------------------------------------------------

반응형

'OS > Common' 카테고리의 다른 글

Z 확장자 압축해제  (0) 2013.07.09
aix hpux solaris 특징 및 명령어 비교  (0) 2012.12.05
ftp 사용법 [명령어]  (0) 2011.10.20
Tar 와 Gzip Bzip2사용법  (0) 2011.10.20
unix/linux의 OS 32/64bit 확인 방법  (0) 2011.10.04
반응형

ftp는 기본적으로 21번 포트를 사용한다.
접속하고자 하는 ip의 21번 포트가 열려 있는지 먼저 확인할 것.

[접속]
ftp [ip 주소]
name : [계정명]
password : [계정 비밀번호]

-----------------------------

FTP 실행 시 옵션

아래는

Dos의 쉘 명령어로

ftp -n -v -s:fileup.txt

를 실행하기위한 fileup.txt 이다.

fileup.txt 의 내용

open 192.168.10.101
user administrator
mypassword //user 유저 비밀번호 //한줄에 다써도 된다
bin // 바이너리모드로 전송
hash // 다운로드 진행상황 '#'표시
prompt off
cd lcgdir
mput 20070910.*

get afile.abc // afile.abc 다운로드실행
bye //ftp 종료

--------------------------------------------------------------------------------------------

FTP [-v] [-d] [-i] [-n] [-g] [-s:filename] [-a] [-w:windowsize] [-A] [host]

-v Suppresses display of remote server responses.
-n Suppresses auto-login upon initial connection.
-i Turns off interactive prompting during multiple file
transfers.
-d Enables debugging.
-g Disables filename globbing (see GLOB command).
-s:filename Specifies a text file containing FTP commands; the
commands will automatically run after FTP starts.
-a Use any local interface when binding data connection.
-A login as anonymous.
-w:buffersize Overrides the default transfer buffer size of 4096.
host Specifies the host name or IP address of the remote
host to connect to.

 

FTP 명령어

---------------------------------------------------------------------

ascii : 전송모드를 ASCII모드로 설정한다.(ascii또는 as)

binary : 전송모드를 BINARY모드로 설정한다.( binary또는 bi)

bell : 명령어 완료시에 벨소리를 나게한다.(bell)

bye : ftp접속을 종료하고 빠져나간다.(bye)

cd : remote시스템의 디렉토리를 변경한다.(cd 디렉토리명)

cdup : remote시스템에서 한단계 상위디렉토리로 이동한다.(cdup)

chmod : remote시스템의 파일퍼미션을 변경한다.(chmod 755 index.html)

close : ftp접속을 종료한다. (close)

delete : remote시스템의 파일을 삭제한다.(delete index.old)

dir : remote시스템의 디렉토리 내용을 디스플레이한다.(dir)

disconnect : ftp접속을 종료한다.(disconnect)

exit : ftp접속을 종료하고 빠져나간다.(exit)

get : 지정된 파일하나를 가져온다.(get index.html)

hash : 파일전송 도중에 "#"표시를 하여 전송중임을 나타낸다.(hash)

help : ftp명령어 도움말을 볼 수 있다.(help또는 help 명령어)

lcd : local시스템의 디렉토리를 변경한다.(lcd 디렉토리명)

ls : remote시스템의 디렉토리 내용을 디스플레이한다. (ls 또는 ls -l)

mdelete : 여러개의 파일을 한꺼번에 지울 때 사용한다.( mdelete *.old)

mget : 여러개의 파일을 한꺼번에 가져오려할 때 사용한다. ( mget *.gz)

mput : 한꺼번에 여러개의 파일을 remote시스템에 올린다.(mput *.html)

open : ftp접속을 시도한다.(open 168.126.72.51또는 open ftp.kornet.net)

prompt : 파일전송시에 확인과정을 거친다. on/off 토글 (prompt)

put : 하나의 파일을 remote시스템에 올린다.(put index.html)

pwd : remote시스템의 현재 작업디렉토리를 표시한다.(pwd)

quit : ftp접속을 종료하고 빠져나간다.(quit)

rstatus : remote시스템의 상황(version, 어디서, 접속ID등)을 표시한다.(rstatus)

rename : remote시스템의 파일명을 바꾼다.(remote 현재파일명 바꿀파일명)

rmdir : remote시스템의 디렉토리을 삭제한다.(rmdir 디렉토리명)

size :remote시스템에 있는 파일의 크기를 byte단위로 표시한다.(size index.html)

status : 현재 연결된 ftp세션모드에 대한 설정을 보여준다.(status)

type : 전송모드를 설정한다.(type 또는 type ascii 또는 type binary)

[출처] DOS에서 FTP사용, FTP 명령어|작성자 이천사


참조:

. FTP 명령어

1) 일반 명령어
* help 또는 ? : 명령어 보기.
* ls : 파일 및 디렉토리 목록 보기. shell에서 ls와 같다.
* dir : 파일 및 디렉토리의 접근 권한과 목록을 자세히 출력.
유닉스쉘에서 ls -al과 같은 효과.
* pwd : 현재 디렉토리 위치 확인.
* cd : Remote System에서 디렉토리 이동.
* lcd : Local System의 디렉토리 변경.
파일 수신시 보관하려는 디렉토리를 변경할 때 사용.
* close : ftp> 프롬프트에서 원격지 시스템의 연결을 끝낸다.
ftp 프로그램은 종료하지 않는다.
* disconnect : 원격지 시스템의 접속 종료. ftp 프로그램은 종료하지 않는다.
* quit 또는 bye : 원격지 시스템의 접속을 종료하고 쉘상태로 복귀한다.

2) 환경 설정 명령어
* bin 또는 binary : binary 파일을 전송하기 위한 세팅.
* ascii : text 파일을 전송하기 위한 세팅.
* prompt : mput 또는 mget 명령시 대화형식 처리를 무시.
* hash : 파일의 전송상황 표시. #로 표시.

3) 파일 전송 명령어
* get : 하나의 파일을 Remote System에서 Local System으로 가져 온다.
* mget : 여러 개의 Local System으로 가져 온다.
* put : 하나의 파일을 Local System에서 Remote System으로 올린다.
* mput : 여러 개의 파일을 Remote System으로 올린다.

4) 기타 명령
* ! : 쉘로 잠시 나가 쉘명령을 수행.
* append : Local 시스템에서 원격시스템으로 파일의 전송시 이어받기.
* bell : 명령어 수행 후 벨소리 On/Off.
* case : 파일 전송시 대,소문자 구분을 변환.
* cdup : 상위 디렉토리로 이동.
* cr : 텍스트 파일 전송시 엔터코드(Carriage Return) 유무를 조정.
* delete : 파일 삭제.
* mdelete : 여러 파일 삭제.
* mode : 파일 전송 모드 선택.
* proxy : 지정된 명령어들을 선택적으로 사용.
* recv : 지정한 파일을 Local 시스템으로 전송받는다.
* remotehelp : 원격시스템의 도움말 출력.
* rename : 파일 이름 변경.
* reset : 지정한 환경을 모두 해제.
* rmdir : 디렉토리 삭제.
* send : 원격시스템으로 파일을 전송한다.
* struct : 전송할 파일의 구조를 지정.
* status : 지정한 환경 선택사항의 현재 상태 표시.
* trace : 패킷라인 검사.
* type : 파일 전송 모드 지정.
* user : 사용자 이름(Name:)과 암호 설정.

반응형
반응형



Tar(Tape Archive)는 지정된 여러 개의 파일들을 아카이브라고 부르는 하나의 파일로 만들거나 하나의 아카이브 파일에 집적되어 있는 여러개의 파일을 원래의 형태대로 추출해 내는 유닉스 쉘 명령어이다. tar 아카이브 파일에는 어떻게 파일명을 적든 상관없지만 tar로 묵었다는 것을 분명히 해주기 위해 ".tar" 라는 파일이름 확장자가 붙는다. tar 아카이브 파일 내에 들어있는 파일들은 압축되는 것이 아니라, 단지 하나의 파일로 모아지는 것뿐이다. tar라는 이름은 파일들이 주로 자기테이프에 백업되고, 이따금씩 검색되기도 하던 때로부터 유래하였다. 그러나, 요즘에는 tar 아카이브가 오히려 유닉스 시스템들간에 파일들을 전송하기 위해 좀더 자주 사용되고 있다.

1) tar 옵션
-c, --create : 새 저장 파일을 만든다.
-f, --file : 저장파일에 저장한다.
-x, --extract, --get : 묶는 것을 푼다.
-v, --verbose : 처리중인 과정을 화면에 보여줌.
-z, --gzip, --unzip : gzip으로 압축을 하거나 푼다. z는 모든 기능 포함. --gzip은 압축, --unzip은 압축해제
ex) tar -cvfz [파일명] [경로명] , tar -xvfz [파일명]

-j, --bzip2 : bzip2으로 압축하거나 푼다.
ex) tar -cvfj [파일명] [경로명] , tar -xvfj [파일명]

-r : tar 파일 끝에 파일을 추가한다.
-A : 압축파일에 tar 파일을 추가해서 넣을 때
ex) tar -rvf [tar 파일 경로] [추가파일 경로]

-p : 원본 파일의 퍼미션 유지
-d : 압축 파일과의 비교 (tar 파일과 해당 파일 시스템간의 차이점 확인시)
-t : 압축파일에 압축된 파일 리스트 확인 (tar 파일의 내용을 확인하고자 할 때 사용)
ex) tar -tvf [tar 파일 경로], tar -tvfz [gz 파일 경로]

2) gzip옵션
-1 : 빨리 압축하기
-9 : 압축률이 좋게 압축
ex) gzip -1 [파일 경로]
-d : 압축풀때
ex) gzip -d [gz 확장자 파일 경로]



반응형

'OS > Common' 카테고리의 다른 글

해당 바이너리의 비트 확인하기  (0) 2012.05.21
ftp 사용법 [명령어]  (0) 2011.10.20
unix/linux의 OS 32/64bit 확인 방법  (0) 2011.10.04
Shell에서 \n(newline) 발동하게 하기  (0) 2011.09.07
### 서버관리 명령  (0) 2011.08.21
반응형

출처 : http://www.ip6.co.kr/?mid=linux_tip&sort_index=readed_count&listStyle=webzine&document_srl=653

LINUX
# getconf LONG_BIT


HP UX

11.xx 일 경우
# getconf KERNEL_BITS
64

10.xx 일 경우
# getconf LONG_MAX
2147483647
(64비트임)로 확인할 수 있습니다

AIX

현재 load된 kernel 이 32-bit 혹은 64-bit 인지 확인하는 명령어
# bootinfo -K
32

사용중인 machine이 32-bit 혹은 64-bit 인지 확인하는 명령어
# bootinfo -y
32


SOLARIS

# isainfo -kv
64-bit sparcv9 kernel modules
현재 이 시스템은 64bit 커널을 가지고 운영을 하는 시스템 이다.

# isainfo -kv
32-bit sparcv kernel modules
이 시스템은 32bit 커널을 가지고 운영을 하는 시스템이다.

# isainfo -v
64-bit sparcv9 applications 32-bit sparc applications
"-v"만 했을 경우 이 시스템에서는 32bit / 64bit 체계의 프로그램을 사용할 수 있다.

# isainfo -v
32-bit sparc applications
이 시스템은 32bit 체계의 프로그램만 구성하여 사용할 수 있다.
반응형

'OS > Common' 카테고리의 다른 글

ftp 사용법 [명령어]  (0) 2011.10.20
Tar 와 Gzip Bzip2사용법  (0) 2011.10.20
Shell에서 \n(newline) 발동하게 하기  (0) 2011.09.07
### 서버관리 명령  (0) 2011.08.21
서버점검 명령어  (0) 2011.08.20
반응형





shell 에서 \n \t 등을 쓰려면 가장 간단한 방법을 찾아보다가..
-e 옵션을 주면 잘 실행되는 것을 확인 할 수 있었다.


$) echo -e "one\ntwo\nthree"
$) one
$) two
$) three


man echo를 보니 요러한 설명이 들어가 있다!
---------------------------------------------------------------------------------------------
설명
       이   맨페이지는 GNU 버전의 echo 를 다룬다.  대부분의 쉘들은 같은 이름, 같은
       기능의 내장 명령을 가지고 있다는 것을기억하기 바란다.

       echo 는 주어진 문자열들을 스페이스로 구분하여 출력하고 맨마지막에는개행문자
       를 출력한다.

   옵션
       -n     마지막에 개행문자를 출력하지 않는다.

       -e     문자열에서 다음 백슬래쉬로 이스케이프된 문자의 번역을 하도록 한다:
              \a     경고음 (벨)
              \b     백스페이스
              \c     마지막 개행문자를 사용하지 않는다.
              \f     폼 피드
              \n     개행문자
              \r     캐리지 리턴
              \t     수평 탭
              \v     수직 탭
              \\     백슬래쉬
              \nnn   ASCII 코드가 nnn (8진수)인 문자
---------------------------------------------------------------------------------------------      

잘 된다. PS1 변수 선언에서 어떠한 부분을 조작해 주면 된다고 하는데
일단 급한 대로 -e 옵션을 사용해야 하겠다. 으아

반응형

'OS > Common' 카테고리의 다른 글

ftp 사용법 [명령어]  (0) 2011.10.20
Tar 와 Gzip Bzip2사용법  (0) 2011.10.20
unix/linux의 OS 32/64bit 확인 방법  (0) 2011.10.04
### 서버관리 명령  (0) 2011.08.21
서버점검 명령어  (0) 2011.08.20
반응형

### 서버관리 명령

l.파일목록보기,소유/허가권 명령어.


1) ls 파일 목록보기.


ls -lahnd file*또는생략.


-l ;상세목록보기(파일명,파일크기,날짜/시간,허가원,소유권,그룹정보등).


-a ;숨겨진 파일을 포함해서 디렉토리 내의 모든 파일보기.


-n ;소유자명,그룹명 대신 Uid,Gid로 보기.


-h ;파일크기를 k,m단위로 보기.


-d ;현재 디렉토리내의 정보만 보기.


2) ls 명령으로 알아보는 상세정보.


ls -la


결과) drwxr_xr_x 2 hanvit hanvit 4k 10월7일10:10 public_html


d(디렉토리)rwx(user rwx)r_x(group)r_x(other) 2(디렉토리수) hanvit(user소유권)hanvit(그룹소유권).


l(심볼릭 링크(hard link,soft link)


b(블록장치:모든 디바이스 드라이버는 파일 시스템을 통해서 접근되는데, 디스크처럼 블록 단위로 입


출력이 이루어지는 장치를 액세스할 때 사용하는 특수 파일이 블록장치파일이다. 예)하드디스크)


c(문자장치 : 모뎀)


3) chmod 파일허가원 변경.


chmod u-x,g+w,o-x public_html


8진법 으로 변경하기.(아래)














4) chown 사용자 소유권 변경.


chown 소유자명 파일명 -R


-R : 하위폴더에 있는 모든 파일 포함.


5) chgrp 그룹 소유권 변경.


chgrp 그룹명 파일명 -R


6) 사용자 소유권/그룹권한 변경.


chown 소유자명:그룹명 파일명 -R





2.파일 관리와 조작.


1) cp 파일복사 cp index.html index.php


cp -i *.conf /temp


-i : 파일복사시 복사여부 확인기능.


2) mv 파일이동


mv -i *.conf /temp


3) ln 파일링크


ln /usr/local/apache/bin/apachectl ./apache


ln -s /usr/local/apache/bin/apachectl ./apache


-s :소프트 링크 != 하드링크


4) find 파일찾기


find / -name[-perm,-type, -user, -group, -nouser, -nogroup, -exec 명령어 {}\;]


/ :찾을 디렉토리 지정.


-name 파일명 : 파일이름으로 찾기.


-perm 모드 : 파일 퍼미션 조건이 맞는 것만 찾기.


-type : 파일 타입(b,c,d,f,l등)을 지정하여 찾기.


-user : 파일 소유권을 지정하여 찾기.


-group : 그룹에 해당하는 파일찾기.


-nouser -nogroup : 소유권이 없이 파일찾기.


-exec 명령어 {} \; :find 명령에 의해 검색된 파일에 대해 명령를 수행할 수 있게 한다.


find /etc -name services -exec grep tcp {} \; |more


5) gzip 파일압축


gzip -d -9 파일명


: 옵션없이 압축한다.


-9 :가장 좋은 압축률로 압축한다.


-d :압축을 푼다.


6) mkdir 디렉토리 생성.


7) rmdir 빈 디렉토리 삭제.


8) pwd 현재 디렉토리 위치를 알아낸다.


9) rm 파일삭제


rm -rf 파일명.


-r : 하위디렉토리 까지 삭제한다.


-f : 삭제여부 확인없이 삭제한다.


10) tar 파일묶기.


tar -cvf mysql.tar /usr/local/mysql : -c 여러파일을 하나의 이름으로 묶느다.


tar -xvf mysql.tar : -x 묶기파일을 푼다.


tar -zxvf mysql.tar.gz gzip으로 압축된파일을 tar로 푼다.


11) cat 파일내용 출력


12) more 한번에 한 화면씩 파일 내용보기.


13) du 디스크 사용량 보기


du -sh /home :홈디렉토리의 사용량을 알아본다.


-s :개별디렉토리별로 크기를 출력하지 말고 합으로 보여준다.


-h :k,m 단위로 보여준다.


14) which 지정된경로에서 파일 찾기.


15) df 디스크 사용가능 용량보기


16) sync : 버펴 내용을 디스크에 비우기





3. 프로세스 조작


1) ps 프로세스 목록보기


ps -auxr


-a :현재 사용자가 실행시킨 프로세스뿐만 아니라 모든 프로세서 보기.


-u :프로세스 소유자를 보여준다.


-x :제어터미널에 없는 프로세스를 보여준다.


-r : 수행중인 프로세스만 보여준다.


출력결과제목 분석:


USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND


USER :프로세스 소유자.


PID :프로세스 고유번호.


%CPU : CPU사용비율


%MEM : 프로세스가 사용한 메모리 비율.


VSZ : 가상 메모리양.


RSS :프로세스가 사용한 실제 메모리 양.


TTY :프로세스의 제어 터미널연결상황.


STAT :프로세스 상태(S :sleep상태,R:cpu사용중,D:인터럽트될 수 없는 sleep,Z:Zombie,W:메모리상주없음, < :높은우선순위 프로세스 N:낮은 우선순위 프로세스 L:메로리 페이지가 잠겨 있음)


START : 프로세스가 시작한 날짜


TIME : 프로세스가 cpu를 사용한 시간.


COMMAND : 프로세스의 이름


2) top : 모니터링 프로그램


3) kill :프로세스 번호로 죽이기


4) killall :프로세스 이름으로 죽이기





4. 기타 명령.


1) who :현재 시스템에 로그인중인 사용자 보기.


2) su : 슈퍼 유저 권한 획득하기.





5. 네트워킹 도구.


1) telnet


2) ftp


3) mail


6. 편집기


1) vi


2) emacs


3) joe


4) pico


##### 크기가 가장 큰 파일, 디렉토리 찾기
가장 큰 디렉토리를 찾으려면,
du -S | sort -n

가장 큰 파일을 찾으려면,
ls -lR | sort +4n

##### 현재 디렉토리의 크기만을 파악할때
[root@dev2 local]# du -c -h --max-depth=0 *
6.4M apache
35M bin
43M dns
1.7M doc
42k etc
1.0k games
42k geektalkd
1.1M gnuws
1.1M include
41k info
19M jakarta-tomcat-3.2.3
0 jre
15M jre118_v3
25M lib
62k libexec
1011k man
1.3M mm.mysql.jdbc-1.2c
937k sbin
3.8M share
1.8M shoutcast-1-8-3-linux-glibc6
5.2M ssl
159M total

##### 시스템 정보 감추기
/etc/inetd.conf 파일을 열어서,
telnet stream tcp nowait root /usr/sbin/tcpd in.telnetd -h


##### 어떤 프로세스가 메모리를 가장 많이 잡아먹고 있는지 알아내기
ps -aux | sort +4n
또는
ps -aux | sort +5n

##### FTP로 들어온 사용자 확인하기
ftpwho
ftpcount


##### 원하지 않는 사용자 죽이기
[root@dream /root]# skill -KILL sunny
위의 명령을 내리면 sunny 라는 사용자를 완전히 추방시킬수 있습니다.
그런데 이렇게 완전히 추방시키는게 아니구, 특정 터미널에 접속해있는 사용자만 추방시켜야 할 때도 있겠죠?
그럴때는

[root@dream /root]# skill -KILL -v pts/14
이런식으로 하면 된다 그럼 pts/14 에 연결되어 있는 사용자가 죽게 됩니다.

less 결과를 vi로 보기
less상태에서 v를 누르면 바로 vi로 감


###### vi에서 블럭 설정하기
alt+v 하면, 라인 단위로 블럭 설정을 할 수 있으며, 해제 하시려면 Esc를 누르면 됩니다.

또한 ctl+v를 하시면, 블럭 단위로 블럭을 설정하실 수 있습니다.

블럭을 설정 하신 뒤,

삭제를 하려면 x
복사를 하려면 y
붙여넣기는 p

man 페이지 프린트하기
man -t vi > vi.ps

####### ping 무시하기
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all

####### 동시에 여러개의 하위 디렉토리 만들기
mkdir -p music/koreanmusic/ost

리로 다시 살리기
boot : vmlinuz root=/dev/hda6

####### 특정 사용자 ftp 접근 막기
/etc/ftpusers 파일에 로그인 네임을 추가하면 됩니다.

ls라는 파일이 포함된 rpm패키지 찾기일단 ls의 절대경로를 알아야 한다. which lswhich로 알아낸 ls의 절대경로로 rpm질의를 한다.rpm -qf /bin/ls
[root@piruks /etc]# which ls
/bin/ls
[root@piruks /etc]# rpm -qf /bin/ls
fileutils-4.0i-2mz

####### 현재 rpm패키지의 의존패키지
rpm -qR 패키지명

현재 디렉토리크기
du -h --max-depth=1 .

바로 이전 디렉토리로 가기
cd -
반응형

'OS > Common' 카테고리의 다른 글

ftp 사용법 [명령어]  (0) 2011.10.20
Tar 와 Gzip Bzip2사용법  (0) 2011.10.20
unix/linux의 OS 32/64bit 확인 방법  (0) 2011.10.04
Shell에서 \n(newline) 발동하게 하기  (0) 2011.09.07
서버점검 명령어  (0) 2011.08.20
반응형

출처 : http://blog.naver.com/sjh9853?Redirect=Log&logNo=80091441578

linux 점검명령어
서버명 : hostname
OS버전 : cat /etc/issue.net
cat /etc/redhat-release
kernel : uname -r
cat /proc/version
cpu : cat /proc/cpuinfo
top
memory : free -m
top
cat /proc/meminfo
swap : free -m
top
cat /proc/swaps
df -m (free size check)
F/S : df -h
log : /var/log/messages.* #tail messages.*


Unix(유닉스) 점검명령어
서버명 : hostname
OS버전체크 : uname -a
showrev
firmware : prtdiag -v
#cd /usr/platform #cd `uname -i` #cd sbin #./prtdiag -v|more
cpu check : psrinfo -v
sar 2 10
ps -ef
memory check : prtdiag -v
swap check : swap -s
df -m (free size check)
flie system : df -h
log view : cd /var/adm/messages.* #tail messages.*
cd /var/log/syslog.* #tail messgaes.*
booting chechk : dmesg
dump or core : /var/crash/[hostname]/*
routing table : netstat -nr
link traffic : netstat -i
disk i/o : iostat -xcPn 2 10


IBM AIX 점검명령어

#uname –amML : 서버 정보 확인

#uname -L : 서버 시리얼넘버 확인

#oslevel –s : OS버전확인(TL SP확인)

#lssrc -g tcpip :

#instfix –i |grep ML(and SP) : OS버전 확인

#lsdev –Cc processor : 프로세서 수 확인

#lsattr –El mem0 : 메모리 용량 확인.

#topas : 시스템(프로세스, 메모리, 네트워크) 체크.

#ls –al .*Com* : 패치 확인.

#errpt |more : 시스템 에러 체크 à errpt –aj [errorID] |more : errpr에 대한 상세내역 확인.

#lsdev –Cc disk : 디스크 확인

#lspv : 디스크 활성상태확인

#lsvg –l [볼륨그룹명] : 볼륩그룹 확인.

#df –g : 파일시스템 용량체크.

#ifconfig – a : ip정보확인

#netstat –rn : 라우트 정보 확인 (디폴트게이트웨이 확인)

#ping 테스트

#lsdev –Cc if : 네트워크 인터페이스 확인

#lsdev –Cc adapter : 네트워크 카드 확인

#lsdev –Cc pci : pci슬롯 확인.

#lscfg –v : FRU 확인. (lsdev –Cc, lsdev –P)

#lsconf : 장치정보

#du –sk * : 하위 디렉토리 및 파일 용량정보 출력

#bootinfo –r

#bosboot -a : 부트이미지 생성

#ps –ef | grep [프로세서명] : 실행중인 프로세서 검색



Windows(윈도우즈) 점검명령어

서버명 : hostname
[내컴퓨터]- [속성]에서 확인
OS버전 : winver (OS버전확인)
[내컴퓨터]- [속성]에서 확인
patch : winver (패치버전 확인)
[내컴퓨터]- [속성]에서 확인
cpu : dxdiag (CPU 클럭확인)
[작업관리자]
memory : dxdiag (메모리 용량확인)
[작업관리자]
F/S : [내컴퓨터]-[드라이브]별 용량확인
log : [관리]-[이벤트뷰어]

반응형

'OS > Common' 카테고리의 다른 글

ftp 사용법 [명령어]  (0) 2011.10.20
Tar 와 Gzip Bzip2사용법  (0) 2011.10.20
unix/linux의 OS 32/64bit 확인 방법  (0) 2011.10.04
Shell에서 \n(newline) 발동하게 하기  (0) 2011.09.07
### 서버관리 명령  (0) 2011.08.21

+ Recent posts