Systems/Unix2014.07.01 08:58

특정한 포트를 점유하고 있는 프로세스를 찾아서 종료시키고 싶을 때가 있다. 프로그램을 실행시키려고 하는데 특정 포트를 점유하는 다른 프로세스가 있어서 실행 시킬 수 없을 때가 그 예다. 


그럴 때는 fuser라는 명령어를 이용해서 간단하게 처리할 수 있다. 가령 TCP 6633 포트를 점유하는 프로세스를 찾아서 종료시키고 싶다면, UNIX 기반 시스템에서는 다음과 같이 하면 된다. 


fuser -k 6633/tcp


수퍼유저 권한이 필요하다면 다음과 같이 하면 된다. -k는 kill과 같은 의미이다. 


sudo fuser -k 6633/tcp


fuser 프로그램은 원래 특정한 파일을 사용하는 프로세스의 PID를 출력해주는 프로그램이다. man fuser를 실행해 보면 그 자세한 사용법을 확인할 수 있다. 


참고 링크:

http://en.wikipedia.org/wiki/Fuser_(Unix)


저작자 표시 비영리 변경 금지
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. 곰탱이

    네이버와 다음에 블로그를 가지고 있으나 표현에 제약이 따라 티스토리를 사용 해보고자 합니다.
    처음이라 미숙한데 초대장을 가지신 블로그에게 초대장을 받는 방법이 있다더군요
    미력하나마 새로운 블로그 형식에 도전코자 하오니 귀하의 초대장을 보내주시면 감사히 쓰겠습니다.
    1best@korea.com

    2014.07.04 08:47 신고 [ ADDR : EDIT/ DEL : REPLY ]

Languages/Erlang2008.09.22 17:19

앞선 글을 통해 Erlang에서 병렬 프로그래밍이 어떻게 이루어지는지 대략이나마 감을 잡으실 수 있었을 거라고 믿습니다. 다시 정리해보자면, 얼랭에서 병렬 프로그램은 프로세스의 집합으로 만들어지고, 프로세스 끼리 메시지를 주고받아 통신하는 방식을 사용해 구현됩니다. 메시지를 보낼때는 Pid ! Message 이런 형식으로 보내고, 받는 쪽에서는 receive 를 사용해 메시지를 받아 처리합니다.

그러면 지금부터는 앞선 글에서 만든 프로그램을 진짜 클라이언트/서버 모델을 만족하도록 바꿔 보겠습니다. 클라이언트가 서버에게 요청을 보내면, 서버는 그 요청을 해석해서 클라이언트에게 답을 보내주어야 합니다. 다음의 코드를 보시죠.

-module(concur).
-export([start_server/0, send_request/2, send_stop/1]).

start_server() -> spawn( fun loop/0 ).

loop() ->
    receive
        {request, Pid, L} ->
            Result = odds_and_evens_acc(L),
            Pid ! {response, self(), Result},
            loop();
        stop ->
            exit
    end.

send_request(Pid, L) ->
    Pid ! {request, self(), L},
    receive
        {response, _SPid, {{odd, Ov},{even,Ev}}} ->
            io:format("odd: ~p, even: ~p~n", [Ov,Ev])
    end.

send_stop(Pid) -> Pid ! stop.

odds_and_evens_acc(L) ->
    odds_and_evens_acc(L, 0, 0).

odds_and_evens_acc([H|T], Odds, Evens) ->
    case ( H rem 2 ) of
        1 -> odds_and_evens_acc(T, Odds + H, Evens);
        0 -> odds_and_evens_acc(T, Odds, Evens + H)
    end;
odds_and_evens_acc([], Odds, Evens) ->
    { {odd, Odds}, {even, Evens} }.

클라이언트/서버 모델을 따르는 통신을 하기 위해, 서버에게 보내는 메시지의 형식이 좀 바뀌었습니다. 메시지가 투플 형태로 간다는 것은 종전과 똑같습니다만, 그 투플의 두 번째 항목에 요청을 보내는 클라이언트 프로세스의 PID가 들어간다는 점이 달라졌습니다. 이 PID가 있어야 서버는 어느 클라이언트에게 응답을 보내야 할 지를 알 수  있죠. 서버는 요청이 오면 odds_and_evens_acc를 호출해서 결과를 계산한 다음에, 요청을 보낸 프로세스에게 응답을 전송합니다. 전송되는 응답 투플 맨 앞에는 '응답'임을 알리기 위해 response라는 아톰이 들어가고, 투플 두번째 항목에는 서버 프로세스의 PID가 들어가고(self()를 호출하면 자기 자신의 PID를 얻을 수 있습니다) 세 번째 항목에는 보낼 계산 결과값이 들어갑니다. 

클라이언트는 서버에게 요청을 보내기 위해 send_request 함수를 이용해야 합니다. 이 함수의 첫번째 인자로는 서버의 PID가 오고, 두 번째 인자로는 리스트가 전달됩니다. send_request는 해당 인자들을 사용해 서버에 메시지를 전송한 다음, 스스로 receive를 통해 그 서버가 보내는 응답을 전송받습니다. 그런 다음 응답을 해석해 화면에 결과값을 뿌리죠. (서버가 보내는 PID는 사용하지 않을 것이기 때문에 _SPid와 같은 이름의 변수를 썼다는 것에 주의합시다. _가 앞에 붙는 변수는 설사 이후의 코드에서 사용되지 않아도 컴파일러가 ok합니다.)

위의 코드는 다음과 같이 사용합니다.

14> c(concur).
{ok,concur}
15> Pid = concur:start_server().
<0.90.0>
16> concur:send_request(Pid, [1,2,3,4,5,6]).
odd: 9, even: 12
ok
17>

이렇게 해서 클라이언트/서버 모델을 따르는 간단한 예제까지 만들어 봤습니다. 이해하기 쉬우셨는지 모르겠군요. 다음 글에서는 실제로 메시지 송수신 과정에서 발생할 수 있는 문제에 대처할 수 있는 코드를 만드는 방법을 포함해, 조금 더 심화된 주제들을 살펴보겠습니다.

머리가 터질거같은 상태에서 억지로 글을 쓰다보니 더 이상 길게는 못쓰겠군요. 머리 터질때 코드 작성하는 일 말고는 할 수 있는게 없는 저 자신도 참 한심하기 짝이 없습니다만....




신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

Languages/Erlang2008.09.05 14:11

C같은 프로그래밍 언어에는 순환문 지원을 위한 다양한 문법들을 제공하고 있습니다. for, while, do-while 등등이 그것이죠. 물론 순환문을 위한 '특별한' 문법을 사용하지 않고도 프로그래밍을 할 수 있긴 합니다. 가령 C의 다음과 같은 프로그램을 한번 생각해 보죠.

int sum(int[] array, size_t n) {
    int sum = 0;
    for ( int i = 0; i < n; ++i ) {
        sum += array[i];
    }
}

for를 사용해 배열에 있는 모든 값들을 합산하고 있습니다. 그런데 for라는 키워드를 사용할 수가 없고, 그냥 함수 개념만 사용해 프로그래밍을 해야 한다면, 문제를 어떻게 해결할 수 있을까요?

int sum(int[] array, size_t n) {
    return sum_array(array, n, 0, 0);
}

int sum_array(int[] array, size_t n, int start_index, int sum) {
    if ( n == 0 ) {
        return sum;
    }

   return sum_array(array, n-1, start_index + 1, sum + array[start_index]);
}

뭐 이렇게도 할 수 있지 않았을까요? 여기서 주목해 볼 것은, 인자 sum을 통해 최종적으로 반환될 합계 값을 추적한다는 점입니다. 이런 프로시저는 "컴퓨터 프로그램의 구조와 해석"이라는 책에서 쓰인 용어를 빌려 말하자면, "되도는 프로시저"이고 "반복적인 프로세스"이죠. (이에 대해서는 해당 책을 참조하시길. ㅋㅋ) 반복적인 프로세스는 재귀적인 프로세스와는 달리 유한한 메모리를 사용해 문제를 풀 수 있습니다. (재귀적인 프로세스는 그 계산과정을 추적하기 위해 재귀 호출이 뻗어나간 각각의 가지에 대한 정보를 계산이 끝나서 그 결과가 '말아올려질 때 까지' 들고 있어야 합니다.)

하지만 C나 Java같은 프로그래밍 언어는 설사 프로세스가 풀려나가는 과정이 반복적(iterative)이라고 하더라도 일단 재귀적인 프로시저를 통해 구현했다면 전부 똑같이 처리합니다. 가령, 위의 sum_array 함수는 네 개의 변수만 사용하면 그 계산과정 전부를 온전히 추적할 수 있음에도, C 컴파일러는 냉정하게 함수가 새로 호출될 때 마다 그에 필요한 스택을 강제로 할당해 버립니다. 결국 배열이 길어지면 stack overflow가 나고 말죠. 그래서 for나 whie, do-while 같은 별도의 문법이 존재하는 겁니다.

하지만 Erlang이나 Scheme같은 프로그래밍 언어는 순환문을 위한 별도의 문법을 제공하지 않습니다. Erlang에서 위의 문제를 어떻게 푸는지 한번 살펴보도록 하죠. 재귀적 프로시저를 사용해 코드를 작성해야 합니다.

sum([H|T]) -> H + sum(T);
sum([]) -> 0.

위의 sum/1 함수는 리스트 하나를 인자로 받습니다. 리스트가 비어 있지 ([]) 않을 경우, 대응 규칙에 따라 이 리스트는 위의 첫 번째 절로 전달됩니다. 첫 번째 절에서 인자는 머리 (H)와 나머지(T) 부분으로 분리됩니다. 그러므로 sum이 반환해야 할 값은 H와 sum(T)의 합이 됩니다. 간단하죠?

그런데 위의 함수는 되도는 프로세스 이지 반복적인 프로세스는 아닙니다. 그다지 효율적으로 메모리를 사용하지 못한다는 뜻이 되겠군요. 이 프로세스를 반복적 프로세스로 바꿀려면, 다음과 같이 해야 할겁니다.

sum(L) -> sum(L, 0).

sum([H|T], S) -> sum(T, H + S);
sum([], S) -> S.

이렇게 하고 Erlang 셸에서 다음과 같이 해 보면 결과가 제대로 출력되는 것을 볼 수 있습니다.

14> L = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].
[1,2,3,4,5,6,7,8,9,10]
15> c(test).
...
20> test:sum(L).
55
21>

결국 Erlang에서 순환문은 함수를 재귀적으로 작성하여 만들게 된다는 이야기입니다. 간단한 이야기를 하려던 것이었는데 말이 너무 길어졌군요 ㅜㅜ 어쨌건 순환문을 만드는 데 있어서 재귀적 프로세스와 반복적 프로세스에 대한 차이는 반드시 알아두는 것이 좋습니다. Erlang에서는 그 차이를 정확하게 이해해야 효율적인 프로그램을 짤 수 있을 것이거든요.

"컴퓨터 프로그램의 구조와 해석"이 좀 비싸긴 합니다만 한권 장만해두시는 것도 좋겠습니다. ㅋㅋㅋㅋㅋㅋ

그럼 보는 김에 "프로그래밍 얼랭"에 나오는 예를 하나 더 살펴볼까요? 완전히 같은건 아니고 제가 좀 바꿨습니다.

odds_and_evens_acc(L) ->
    odds_and_evens_acc(L, 0, 0).

odds_and_evens_acc([H|T], Odds, Evens) ->
    case ( H rem 2 ) of
        1 -> odds_and_evens_acc(T, Odds + H, Evens);
        0 -> odds_and_evens_acc(T, Odds, Evens + H)
    end;
odds_and_evens_acc([], Odds, Evens) ->
    { {odd, Odds}, {even, Evens} }.


29> c(test).
{ok,test}
30> test:odds_and_evens_acc(L).
{{odd,25},{even,30}}
31>

홀수끼리의 합, 짝수끼리의 합을 구해서 투플 형태로 반환하는 예입니다. case 문도 사용했고, 투플에 아톰을 넣어뒀기 때문에 반환값의 의미를 좀 명확하게 볼 수 있습니다.


신고
Posted by 이병준

소중한 의견, 감사합니다. ^^