http://blog.ilovelinux.org/2009/10/edge-trigger-level-trigger.html

최신 내용은 위 주소로 방문하세요.

=============================================================




두 트리커의 차이점은 소켓버퍼에 데이터가 있는 경우에 그것을 소켓 이벤트로 간주하는 기준이다.

먼저, 쉬운것부터...

레벨트리거: 소켓버퍼에 데이터가 들어있으면 무조건 이벤트가 발생하는 트리거이다. 즉, 소켓에서 read 할 수 있는 데이터가 1바이트 이상 있을때 이벤트가 발생했다고 리턴해준다. 여기서 1바이트라고 했지만 그 기준을 소켓옵션설정을 통해 조정할 수 있는 것으로 알고 있다. 이것을 조정하면 10바이트 이상일 경우에만 이벤트가 발생하는 것으로 기준을 설정할 수도 있다. (select(), poll() 등이 레벨트리거에 속한다.)

에지트리거: 소켓버퍼의 데이터가 들어오는 시점을 알려주는 이벤트 트리거이다. 소켓버퍼가 비어 있다가 상대방으로부터 버퍼에 데이터가 들어오면 이때 이벤트가 발생한 것으로 간주한다. 들어온 데이터를 어플리케이션에서 read 하고 안하고는 무관하다. 즉, 에지트리거에서 이벤트가 발생했고(데이터가 들어왔고), 어플리케인션에서 read 하지 않더라도 그 이후에 다른 데이터가 추가로 들어오면 에지트리거는 이벤트가 발생했다고 리턴하게 된다. (epoll(), kqueue() 등이 에지트리거에 속한다. 이것들은 설정에 따라 레벨트리거로도 사용할 수 있다.)

일반적으로.... 에지트리거가 대량의 접속시에 더 나은 응답속도를 제공한다.
(이벤트 처리가 빠르다.)

이해를 돕기 위해서 그림하나 추가해 본다.

사용자 삽입 이미지



에지트리거를 다룰 때 주의점:
에지트리거를 통해 이벤트 받았고 read 작업을 해야하는데, 이 시점에 read 할 수 있는 모든 데이터를 read 해야한다. 왜냐하면, 에지트리거는 데이터 유입에 대한 이벤트이므로 추가로 데이터 유입이 없으면 이벤트가 오지 않으므로 이번 이벤트를 통해 read를 할 때 다음에 다시 이벤트가 온다는 보장이 없으므로 이 시점에 읽을 수 있는 모든 데이터를 read 해야만 정상적인 처리가 된다. 어플리케이션의 read 버퍼가 작아서 꽉찬 상태로 리턴되면 이것을 다른 버퍼에 저장해 두고, 나머지를 다시 소켓으로부터 read 해야한다. 더 읽을 것이 없을때까지 계속 read 해야 한다. 이번에 read를 다 하지 않으면 영원히 다시 read할 이벤트가 오지 않을 수 있기 때문이다.


Posted by sjang


Leave a comment

http://blog.ilovelinux.org/2009/10/epoll-echo-server.html
최신내용은 위 주소를 방문하세요.

=============================================================



C로 만든 echo server 이다.
최고 성능이라고 평가받는 epoll()를 사용하였다.
accept()를 사용하는 서버소켓은 Level Trigger를 사용하고, 클라이언트와 연결된 소켓은 Edge Trigger를 사용하였다. Non-blocking 소켓을 다루는 기본 방법에 대해서도 첨부된 예제를 통해 배울 수 있다.

첨부된 파일은 epoll를 다루는 라이브러리를 제작하고, 그것을 사용하는 예제로 echo server를 제작한 것이다. 라이브러리를 통해 epoll에서 소켓을 어떻게 등록하고 해제하는지 알 수 있다.

아래에 echo server의 구현 코드를 보였다.

여기서 몇몇 에러처리가 빠져있는데, Non-blocking 소켓의 read에서 EAGIN 에러처리와 소켓 연결이 끊기는 이벤트를 감시하지 않은 것, 그리고 read 시에 버퍼를 넘었을 경우에 수신한 내용을 다른 곳에 저장하고 계속 read 해야 하는 것 등등...
(Edge Trigger를 사용할 경우에는 read 시에 모두 읽어와야 한다. 왜냐하면, 다시 이벤트가 온다는 보장이 없으므로 이벤트가 왔을 때 모두 Read 해야 한다.)

그러나, non-blocking 에서의 write 방법에 대해서는 정확하게 구현하였다.
다음의 내용처럼....
(non-blocking 소켓에서 write()를 수행할 경우에 write 하고자 하는 length만큼
write가 되지 않을 수 있음을 알아야 합니다.
예를 들어, 100바이트를 보내기 위해 write() 함수를 호출했을 때, 100바이트를 다 보내지 못하고 리턴됩니다. 리턴될 때, 보낸 length를 반드시 체크해야 합니다. 아마도 대부분의 경우에 100이 리턴되겠지요. 하지만, 네트웍이 바쁘거나 상태가 좋지 않거나 접속이 많은 경우에는 100보다 작은 숫자가 리턴됩니다. 원하는 바이트길이만큼 보내지 못한 것이지요. 이럴때에는 어떻게 해야할까요? 다시 write()를 바로 호출해야할까요? 그렇게 처리할 수도 있지만 바로 직전에 왜 100바이트를 모두 전송하지 못했는지를 이해한다면 그렇게 처리하는 것이 바람직하지 않습니다. 송신버퍼에 100바이트를 채울 여유가 없기때문에 100보다 작은 숫자가 리턴되는 것이기때문에 바로 다시 write()를 호출한다고해서 남은 바이트가 바로 전송된다는 보장이 없습니다.
write()처리를 이벤트를 통해서 해야하는 이유가 여기에 있습니다. 100바이트를 모두 보내지 못했을 때, 그 소켓의 writable를 계속 체크해서 그 이벤트가 오면(송신버퍼에 빈공간이 생기면) 그 시점에 write()를 호출하면 되는 것이죠.
따라서, non-blocking의 read/wirte는 소켓 이벤트의 결과에 따라 일괄적으로 처리를 해주어야 합니다.)

write를 이벤트로 처리해야함은 필수사항이다. 대부분의 epoll 예제가 이 부분을 따로 처리하지 않았지만, 이는 네트웍상태가 좋지 않거나 클라이언트가 바쁘거나 등등의 이유로 원하는 크기를 전송할 수 없는 경우에 필수적인 에러처리이다.
(스티븐 아저씨의 책에서도 명확하게 나와있음)

라이브러리 및 예제에서 사용한 것들...

1. TAILQ: 리눅스에서 기본제공하는 큐이다. 이것을 이용해서 echo 데이터 저장큐로 사용하였다. man page를 보면 친절한 예제와 함께 설명이 있다.
2. myapp.h: 이 헤더파일과 echo_server.[ch] 파일을 함께 보기 바란다. 라이브러리를 사용하여 구현이 쉽도록 하기 위해서 echo 뿐만 아니라, 다른 자료구조를 도입하기 쉽도록 void * 를 이용하여 어플리케이션 원하는 자료구조를 쉽게 구성할 수 있게 하였다.
3. 최대처리수: 최대 클라이언트 수를 소스안에 define를 통해 설정하게 하였다. 물론, 시스템 설정이 지원하는 최대개수 이내만 가능하다.

아쉬운 점....
doxygen를 이용하여 소스코드 문서를 만들어서 올릴 필요가 있겠다.. ^^

echo_server.c 소스
---------------------------------------------------------------------
  1 #include "epollio.h"
  2 #include "socket_util.h"
  3 #include "myapp.h"
  4
  5 #include <stdio.h>
  6 #include <stdlib.h>
  7 #include <string.h>
  8 #include <unistd.h>
  9 #include <sys/types.h>
 10 #include <sys/socket.h>
 11 #include <arpa/inet.h>
 12
 13 #include "echo_server.h"
 14
 15
 16 #define MAX_CLIENT 1000
 17
 18 int recv_count = 0;
 19 int send_count = 0;
 20
 21 static void reset_myapp_data(myapp_data_t *myapp_data)
 22 {
 23     echo_data_t *echo_data = (echo_data_t *)myapp_data->data;
 24
 25     close(myapp_data->socket_fd);
 26     myapp_data->socket_fd = -1;
 27
 28     memset(echo_data->client_ip, 0, sizeof(echo_data->client_ip));
 29     memset(echo_data->in_msg, 0, sizeof(echo_data->in_msg));
 30     memset(echo_data->out_msg, 0, sizeof(echo_data->out_msg));
 31     echo_data->in_msg_len = 0;
 32     echo_data->out_msg_len = 0;
 33     echo_data->sent_len = 0;
 34 }
 35
 36
 37 void init_myapp_data_members(myapp_data_t *myapp_data)
 38 {
 39     reset_myapp_data(myapp_data);
 40 }
 41
 42
 43 int init_myapp_data(myapp_data_t **mydata, int max_client)
 44 {
 45 /*  myapp_data_t *myapp_temp;*/
 46 /*  echo_data_t *echo_temp;*/
 47     int i;
 48
 49     for(i = 0; i < max_client; i++)
 50     {
 51         if ((mydata[i] = (myapp_data_t *)malloc(sizeof(myapp_data_t))) == NULL)
 52         {
 53             return -1;
 54         }
 55
 56         /* 응용 데이터 공간을 queue 공간의 데이터 포인터에 할당 */
 57         if ((mydata[i]->data = (echo_data_t *)malloc(sizeof(echo_data_t))) == NULL)
 58         {
 59             return -1;
 60         }
 61 /*      mydata[i]->data = (echo_data_t *)echo_temp;*/
 62 /*      printf("myapp data Pointer [%x]\n", mydata[i]);*/
 63 /*      printf("echo data Pointer [%x]\n", mydata[i]->data);*/
 64
 65         mydata[i]->socket_fd = -1;
 66         init_myapp_data_members(mydata[i]);
 67
 68         /* 확보한 공간을 Queue 안에 넣는다. */
 69         if (i == 0)
 70         {
 71             TAILQ_INSERT_HEAD(&myapp_data_event_queue, mydata[i], mydata_next);
 72         }
 73         else
 74         {
 75             TAILQ_INSERT_TAIL(&myapp_data_event_queue, mydata[i], mydata_next);
 76         }
 77     }
 78     return 0;
 79 }
 80
 81 static int recv_msg(int fd, echo_data_t *echo_data)
 82 {
 83     int recv_len;
 84     int buf_len = sizeof(echo_data->in_msg) - 1;
 85     recv_len = recv(fd, echo_data->in_msg, buf_len, 0);
 86     if (recv_len < 0)
 87     {
 88         /* non-blocking 소켓이므로 여기서 errno 체크해야함 */
 89         return -1;
 90     }
 91     if (recv_len == 0) /* 끊어진 소켓 */
 92     {
 93         return -1;
 94     }
 95     echo_data->in_msg_len = recv_len;
 96     recv_count++;
 97     printf("in msg = [%s]\n", echo_data->in_msg);
 98     printf("in msg len = [%d]\n", echo_data->in_msg_len);
 99
100     return 0;
101 }
102
103 static int send_msg(int fd, echo_data_t *echo_data)
104 {
105     int sent_len;
106
107     printf("send buf = [%s]\n", echo_data->out_msg + echo_data->sent_len);
108     sent_len = send(fd, echo_data->out_msg + echo_data->sent_len, echo_data->out_msg_len - echo_data->sent_len, 0);
109     if (sent_len < 0)
110     {
111         printf("send_msg error\n");
112         return -1;
113     }
114     printf("sent len = [%d]\n", sent_len);
115
116     echo_data->sent_len += sent_len;
117
118     return 0;
119 }
120
121
122 int echo_server_process(struct epoll_event *event)
123 {
124     myapp_data_t *myapp_data;
125     echo_data_t *echo_data;
126
127     myapp_data = (myapp_data_t *)(event->data.ptr);
128 /*  printf("echo server myapp_data process Pointer [%x]\n", myapp_data);    */
129     echo_data = (echo_data_t *)(myapp_data->data);
130 /*  printf("echo server echo_data process Pointer [%x]\n", echo_data);  */
131
132     if (event->events & EPOLLIN)
133     {
134         if (recv_msg(myapp_data->socket_fd, echo_data) < 0)
135         {
136             printf("recv msg error\n");
137             return -1;
138         }
139         printf("in msg copy [%s]\n", echo_data->in_msg);
140         strncpy(echo_data->out_msg, echo_data->in_msg, echo_data->in_msg_len);
141         printf("out msg [%s]\n", echo_data->out_msg);
142         echo_data->out_msg_len = echo_data->in_msg_len;
143
144         /* reset read buf */
145         memset(echo_data->in_msg, 0, sizeof(echo_data->in_msg));
146         echo_data->in_msg_len = 0;
147
148         printf("writable on\n");
149         /* writable check로 변경. */
150         if (set_event_socket(&ed, myapp_data->socket_fd, EVENT_WRITE, myapp_data, FD_MODIFY) < 0) /* echo server 이므로 EVENT_READ가 설정되어야 한다. */
151         {
152             fprintf(stderr, "epoll set insertion error: fd=%d", myapp_data->socket_fd);
153             return -1;
154         }
155     }
156     else if (event->events & EPOLLOUT)
157     {
158         if (send_msg(myapp_data->socket_fd, echo_data) < 0)
159         {
160             printf("recv msg error\n");
161             return -1;
162         }
163
164         printf("out msg len = [%d]\n", echo_data->out_msg_len);
165         if(echo_data->out_msg_len == echo_data->sent_len)
166         {
167             /* reset write buf */
168             memset(echo_data->out_msg, 0, sizeof(echo_data->out_msg));
169             echo_data->out_msg_len = 0;
170             echo_data->sent_len = 0;
171
172             send_count++;
173
174             printf("readable on\n");
175             /* readable check로 변경. 즉, 받은데이터를 모두 echo 하기 전에 다시 받지 않음 */
176             if (set_event_socket(&ed, myapp_data->socket_fd, EVENT_READ, myapp_data, FD_MODIFY) < 0)
177             {
178                 fprintf(stderr, "epoll set insertion error: fd=%d", myapp_data->socket_fd);
179                 return -1;
180             }
181         }
182     }
183     return 0;
184 }
185
186 int main()
187 {
188     int nfds;
189     int listener;
190     int client_fd;
191     struct sockaddr_in local;
192     socklen_t addrlen;
193     int n;
194
195
196
197     myapp_data_t *new_myapp_data;
198
199
200     myapp_data_t *myapp_data[MAX_CLIENT]; /* 현재 응용의 처리를 위한 데이터 구조체의 공간 확보 */
201
202     TAILQ_INIT(&myapp_data_event_queue);
203
204     if (init_myapp_data(myapp_data, MAX_CLIENT) < 0)
205     {
206         printf("init echo data error\n");
207         return -1;
208     }
209
210     if ( init_epoll(&ed, 10000) < 0 )
211     {
212         printf("epoll_init error!\n");
213         return -1;
214     }
215
216     addrlen = sizeof(local);
217
218     listener = make_socket(10025);
219     if (listener < 0)
220     {
221         return -1;
222     }
223
224     if (add_epoll_listen_socket(&ed, listener, EVENT_READ) < 0 )
225     {
226         return -1;
227     }
228
229     while(1)
230     {
231         printf("--------------------------\n");
232         printf("recv count = [%d]\n", recv_count);
233         printf("send count = [%d]\n", send_count);
234         printf("--------------------------\n");
235         nfds = epoll_event_monitor(&ed, -1);
236         if (nfds < 0)
237         {
238             return -1;
239         }
240         printf("returned event [%d]\n", nfds);
241
242         for(n = 0; n < nfds; ++n)
243         {
244             if(ed.events[n].data.fd == listener)
245             {
246                 new_myapp_data = (myapp_data_t *)get_new_mydata();
247                 client_fd = accept(listener, (struct sockaddr *) &local, &addrlen);
248                 if(client_fd < 0)
249                 {
250                     perror("accept");
251                     continue;
252                 }
253
254 /*              printf("new_myapp_data Pointer [%x]\n", new_myapp_data);*/
255                 if (set_event_socket(&ed, client_fd, EVENT_READ, new_myapp_data, FD_ADD) < 0) /* echo server 이므로 EVENT_READ가 설정되어야 한다. */
256                 {
257                     fprintf(stderr, "epoll set insertion error: fd=%d", client_fd);
258                     return -1;
259                 }
260             }
261             else
262             {
263 /*              printf("ed event Pointer 1[%x]\n", &ed.events[n]);*/
264                 if (echo_server_process(&ed.events[n]) < 0)
265                 {
266                     /* delete 추가 */
267                     myapp_data_t *myapp_data_temp = (myapp_data_t *)ed.events[n].data.ptr;
268                     reset_myapp_data(myapp_data_temp);
269                     /* 다시 queue로 반환한다. */
270                     TAILQ_INSERT_TAIL(&myapp_data_event_queue, myapp_data_temp, mydata_next);
271                 }
272             }
273         }
274     }
275     return 0;
276 }
277

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


Posted by sjang


Comments List

  1. sjang 2008/03/26 16:47 # M/D Reply Permalink

    내용수정!!
    스티븐 아저씨의 책에서 Non-blocking I/O에 대한 부분을 다시한번 읽었다. write()처리에 대한 것이다.

    select()를 이용한 구현을 다시보니, read 후에, 바로 write 비트를 켜서 select로 다시 루프를 돌지 않고 바로 write를 시도했다. 물론, write length를 체크해서 다시 write 할 필요가 있는지 검사하고 더 있다면 write bit를 계속 켜두게(reset하고 다시 켜기)하고 있다.

    이 부분의 구현은 구현자 마음이라는 코멘트가 있었다. 바로 write 하지 않고 비트만 켜서 select를 통해 처리하는 것과(이 방법은 루프한번의 오버헤드가 있다.) read 후에 바로 write를 수행하고 더 보낼게 남았으면 write 비트를 키는 방식이 있다고 했다. 물론, Writable를 체크하지 않고 쓰기때문에 write() 콜에서 EWOULDBLOCK를 발생(소켓에 쓰기를 받아줄 공간이 없는상태)할 수 있다.

    어느 방법을 이용하든 구현자의 마음이다. 무작정 write를 한번 시도해보고 더 보낼게 있을때에만 write 비트를 키는 방법도 괜찮은거 같다.

  2. serahero 2009/01/28 20:28 # M/D Reply Permalink

    epoll 과 thread를 조합해보고자 공부하는데 많은 도움 되었습니다.

    피드 등록 할려했더니 블로그를 안하시네요 안타까움..ㅜ_ㅜ.

Leave a comment

iso 만드는 프로그램

사용자 삽입 이미지


간편하게 iso 만들 수 있는 프로그램을 소개합니다.
단, CD에 들어있을 때에만 그것을 iso로 만들 수 있습니다.

For the latest version turn to: http://www.lucersoft.com

Posted by sjang


Leave a comment

free virtual cdrom

iso 이미지 파일을 CD에 마운트해서 사용할 수 있는 많은 상용 프로그램이 있습니다만,
프리웨어를 찾아 헤맨 끝에 그나마 간단하고 괜찮은 녀석을 찾았습니다.

winxpvirtualcdcontrolpanel_21.exe

마이크로소프트에서 프리로 주는 프로그램 입니다.

아래는 readme 파일의 내용입니다. 내용에 나와 있는 순서대로 따라만 하면 어렵지 않습니다.
여러개의 virtual cdrom를 생성할 수 있고, 각각에 다른 iso 파일을 마운트 할 수 있습니다.


사용자 삽입 이미지




Readme for Virtual CD-ROM Control Panel v2.0.1.1

THIS TOOL IS UNSUPPORT BY MICROSOFT PRODUCT SUPPORT SERVICES


System Requirements
===================
- Windows XP Home or Windows XP Professional

Installation instructions
=========================
1. Copy VCdRom.sys to your %systemroot%\system32\drivers folder.
2. Execute VCdControlTool.exe
3. Click "Driver control"
4. If the "Install Driver" button is available, click it. Navigate to the %systemroot%\system32\drivers folder, select VCdRom.sys, and click Open.
5. Click "Start"
6. Click OK
7. Click "Add Drive" to add a drive to the drive list. Ensure that the drive added is not a local drive. If it is, continue to click "Add Drive" until an unused drive letter is available.
8. Select an unused drive letter from the drive list and click "Mount".
9. Navigate to the image file, select it, and click "OK". UNC naming conventions should not be used, however mapped network drives should be OK.

You may now use the drive letter as if it were a local CD-ROM device. When you are finished you may unmount, stop, and remove the driver from memory using the driver control.

팁:
드라이브를 생성하고 iso 파일을 마운트 하더라도 리부팅하면 드라이브가 없어집니다.
마운트할 iso를 선택한 후에, Special Mount Option에서 Persistent mount를 체크하면 리부팅 후에도 드라이브가 사라지지 않고 마운트가 유지됩니다.


Posted by sjang


Leave a comment

시스템 구성을 그리는 일을 해야한다면 파워포인트로 박스 그리고 선 그리고 하는 작업이 매우 귀찮다는 사실을 알게 된다. 그렇다고, visio를 쓰자니 무겁고, 또 회사에서 정품을 사용해야한다는 압박에 어둠의 버전을 설치하기도 깨름직하다.

visio 만큼은 아니지만 무료로 쓸 수 있는 프로그램을 소개한다. 바로 dia

 
 

visio의 스텐실에 결코 뒤지지 않는다.
저장의 다양한 포맷도 지원한다.

윈도우와 리눅스 모두 사용가능하다.


Posted by sjang


Comments List

  1. dfg 2011/11/30 13:10 # M/D Reply Permalink

    fgdfg

Leave a comment
주위를 잘 살펴보면 굳이 돈을 주고 구입하지 않아도 사용이 가능한 공개 소프트웨어가 많이 있다. 이런 소프트웨어들은 무료로 사용 가능하지만 유료로 판매되는 상용 소프트웨어에 버금가는 기능과 성능을 가지고 있어 잘 활용하면 컴퓨터를 보다 편리하게 사용할 수 있으며 다양하게 컴퓨터를 활용할 수 있게 해준다. 이런 소프트웨어 어떤 것이 있으며 이들을 활용하는 방법을 알아보자.

KMPlayer
사용환경 : Microsoft Windows
공식 홈페이지 : http://www.kmplayer.com/


동영상을 보기 위한 소프트웨어들은 많다. 하지만 대다수의 동영상 플레이어는 광고를 포함하고 있다. 여기서 소개하고자 하는 KMPlayer은 어떠한 광고도 포함하지 않은 순수 무료 소프트웨어 이다. 동영상 재생을 위한 각종 동영상 코덱(압축된 동영상을 실시간으로 압축을 해제하여 감상할 수 있게 해 주는 모듈)들을 자체 내장하고 있어 추가로 동영상 코덱 소프트웨어를 설치하지 않아도 되는 편리함을 제공한다. 또한 일일이 말로 설명하기 하기 힘들 정도로 다양한 기능들을 많이 가지고 있다. 따라서 동영상 재생에 대해 지식만 있다면 자신에게 최적화된 형태로 동영상을 감상할 수 있게 해준다. 그 이외에도 DVD/비디오 CD 재생 기능, TV 장치 재생 심지어는 MP3 플레이어로도 사용할 수 있다. 단, 너무나도 많은 옵션을 제공해 처음 사용하는 사람들에게는 다소 복잡하다고 느껴질지도 모른다. 이런 사용자라면 옵션을 변경하지 않고 동영상 감상에만 사용해도 된다.

사용 방법은 다음과 같다.
  1. KMPlayer 프로그램을 다운로드 받아서 설치를 원하는 위치에 압축을 해제한다.
  2. KMPlayer.exe를 실행한다.
  3. 재생을 원하는 동영상을 끌어다 놓기 또는 열기를 통해 감상하면 된다.



대부분 동영상들이 2개 또는 3개로 나뉘어져 있는데 이런 파일들도 자동으로 이어져 재생이 되므로 한번 감상중인 영화는 계속 연이어 감상할 수 있다.


NexusFile
사용 환경 : Microsoft Windows
공식 홈페이지 : http://xiles.net


윈도우에는 탐색기(Explorer.exe)라는 자체 프로그램으로 폴더 및 파일에 접근할 수 있게 해 준다. 하지만 뭔가 2% 부족하다는 느낌이 들 때가 많다. 이럴 때 사용하면 좋은 윈도우 탐색기를 대체할만한 파일 관리자인 NexusFile는 무료이면서 매우 다양하고 강력한 기능들을 제공한다.



NexusFile의 주요 기능을 살펴보면 다음과 같다.
  • 파일의 복사/이동/삭제 등 기본적인 파일 관리
  • 고급 파일 이름 변경
  • 즐겨찾기 폴더 및 지정 폴더로 빠르게 이동
  • 경로명 복사
  • 압축파일 관리
  • 파일 합치기/나누기
  • 파일 목록 저장
  • 트리 구조의 폴더 이동
  • FTP/네트워크 드라이브 연결

사용 방법은 다음과 같다.
  1. NexusFile을 다운로드 받아서 설치를 원하는 폴더에 압축을 해제한다.
  2. NexusFile.exe를 실행한다.
  3. 원하는 파일 작업을 수행하면 된다.

F10키를 누르면 예전 도스(DOS)를 사용할 때 자주 보았던 NCD나 MCD등과 같은 프로그램 형태와 같은 폴더 관리자가 실행된다. 폴더 관리자에서 바로가기 키를 지원하므로 찾고자 하는 폴더를 키보드로 입력하면 해당 폴더로 이동된다.



또한 F12키를 누르면 NexusFile에서 사용 가능한 다양한 단축키 목록을 보여준다. NexusFile를 사용하면 보다 빠르고 편리하게 파일 및 폴더를 관리할 수 있다.


Unstoppable Copier
사용 환경 : Microsoft Windows
공식 홈페이지 : http://www.roadkil.net/unstopcp.html/


최근 CD나 DVD등이 심한 긁힘으로 인해 파일을 복사할 수 없거나 동영상을 볼 수 없는 문제가 생겨 발만 동동 굴러야 할 때가 있다. 이럴 때 읽지 못하는 데이터 부분은 건너뛰고 나머지 데이터라도 복사하고 싶은 이들에게 매우 유용한 소프트웨어가 Unstoppable Copier이다. 일반적으로 동영상의 경우 최근 나오는 플레이어들은 오류가 있는 데이터는 건너뛰고 재생하는 기능을 가지고 있는 경우가 많다. 따라서 일부분이 없다 하더라도 그 부분을 제외하곤 재생이 가능한 경우가 있어 급할 때 사용하면 좋다.

사용 방법은 다음과 같다.
  1. Unstoppable Copier을 다운로드 받아 설치를 원하는 디렉터리에 압축을 해제한다.
  2. 프로그램을 실행하고 복사를 원하는 폴더나 파일을 Source에 입력하거나 [Browse]버튼을 눌러 선택한다.
  3. 2번에서 선택한 폴더나 파일들이 복사될 경로를 Target에 입력하거나 [Browse]버튼을 눌러 선택한다.
  4. [Copy]버튼을 눌러 복사를 시작한다.



복사가 되지 않는 파일들을 복사하고자 할 때 매우 유용하다. 하지만 디스크에서 아예 읽지 못하는 데이터를 복원하는 기능은 제공할 수 없으므로 이점은 유의해야 한다. 가능한 읽기 가능한 데이터는 모두 복사해주는 Unstoppable Copier로 그냥 버릴 수 밖에 없었던 소중한 데이터의 일 부분을 찾아 보기 바란다.


빵집
사용환경 : Microsoft Windows
공식 홈페이지 : http://www.bkyang.com/


파일을 압축하고 해제하는 여러 소프트웨어들이 있다. 비영리를 목적으로 한 개인 사용자들에겐 무료이지만 기업, 공공기관 등에서는 제품을 구매해야 정식으로 사용 가능한 형태로 되어 있어 사용에 제한을 받는 경우가 많다. 하지만 어떠한 상황에서도 무료인 압축 소프트웨어가 있으며, 그 대표적인 제품이 바로 빵집이다. 빵집의 경우 어떠한 경우라도 무료로 사용할 수 있다. 그리고 빵집이 해제할 수 있는 압축 파일 형식 또한 아래와 같이 37개를 지원한다.

빵집이 지원하는 파일 형식 : 001, ace, alz, arc, arj, b64, bh, bz2, cab, ear, enc, gz, ha, ice, jar, lha, lzh, mim, mme, pak, pk_, pk3, rar, tar, tgz, uu, uue, war, wal, wsz, xxe, z, zip, zoo, iso, tbz, 7z

빵폴더와 같이 재미난 폴더 생성 방법을 제공해 단순할 수 있는 폴더 생성을 좀더 재미있게 할 수 있다.
탐색기 메뉴의 미리 보기 기능을 지원해서 압축 파일에 마우스 커서를 놓고 오른쪽 버튼을 누르면 해당 압축 파일의 내용을 미리 확인할 수 있다. 그리고 자동 압축 풀림을 생성할 수 있는 스크립트 마법사를 제공해 별도의 압축 프로그램 없이도 바로 실행해서 압축을 해제할 수 있는 압축 파일을 생성할 수 있는 기능도 제공한다.

사용 방법은 홈페이지에서 프로그램을 다운로드 받아서 설치하면 된다.




FileZilla
사용 환경 : Microsoft Windows, Linux
공식 홈페이지 : http://filezilla.sourceforge.net


FTP(File Transfer Protocol)을 사용하기 위해서는 윈도우내에 포함된 FTP 소프트웨어를 이용하는 방법과 별도의 FTP 소프트웨어를 사용하는 방법이 있다. 윈도우내에 포함된 FTP를 사용하기 위해서는 어려운 명령어를 외워야 가능하며 여러 가지 파일들을 선택적으로 업로드 및 다운로드 하려면 파일 수만큼 명령어를 입력해야 하는 등 어려움이 따른다. 그렇다고 별도의 FTP 소프트웨어를 사용하자니 소프트웨어를 구매해야 하는 부담이 있다. 하지만 FileZilla라는 무료 FTP Client 소프트웨어를 사용하면 이런 어려움과 부담감을 모두 날려버릴 수 있다.
FileZilla는 오픈소스(Open Source) 프로젝트로 모든 소스가 공개되어 있다. 따라서 프로그램 자체도 당연히 무료이다. 무료로 제공되지만 기능과 성능은 다른 어떤 프로그램보다도 뛰어나다. 또한 다국어를 지원해 한국어 윈도우에서 실행하면 자동으로 모든 메시지가 한글로 표기된다.

사용방법은 다음과 같다.
  1. FileZilla프로그램(설치본과 ZIP 압축본 2가지가 있는데 편의상 설치본을 다운로드 받는것이 좋다)을 다운로드 받아 설치한다.
  2. 접속하고자 하는 FTP 서버에 접속하고 파일을 송수신 한다.



또한 추가적으로 FileZilla Server버전을 제공한다. Server버전은 FTP Server를 무료로 구축할 수 있게 해 준다. 윈도우의 경우 FTP Server의 경우 돈을 주고 구매해야 하지만 FileZilla Server를 사용하면 어떠한 추가 금액 없이 자유롭게 서버 운용이 가능하다.


Notebook Hardware Control
사용환경 : Microsoft Windows
공식 홈페이지 : http://www.pbus-167.com/


노트북을 사용하다 보면 발열로 인해 갑자기 셧다운 되거나 또는 배터리가 너무 빨리 소모되어 원하는 작업을 수행하지 못할 경우가 종종 있다. 이는 노트북 CPU가 지속적으로 높은 속도로 동작했기 때문에 발생하는 문제이다. 실제 노트북용 CPU는 처리되는 작업량에 따라 CPU의 속도 및 전압을 조절할 수 있는 기능을 제공한다. CPU에 처리를 요하는 작업량이 증가하면 빠른 속도로 동작하며, CPU에 처리를 요하는 작업량이 줄어들면 느린 속도로 동작하게끔 설계가 되어 있다. 이 속도는 임의로 조절이 가능하며 경우에 따라 고정해서 사용할 수도 있다. 이러한 기능을 가능하게 해주는 소프트웨어가 바로 Notebook Hardware Control(NHC)이다. 하지만 이 소프트웨어는 Microsoft .Net Framework 2.0을 기반으로 제작되어 있어 만약 Microsoft .Net Framework 2.0이 없다면 이를 먼저 설치해야만 정상적으로 동작한다.

사용 방법은 다음과 같다.
  1. Microsoft .Net Framework 2.0이 설치되어 있지 않다면 설치한다.
  2. Notebook Hardware Control(NHC)를 다운로드 받아 설치한다.
  3. 윈도우 트레이 아이콘에 등록된 NHC아이콘에 마우스 커서를 놓고 오른쪽 버튼을 눌러 CPU의 작동 모드를 선택한다.

  4. 작동모드는 Standard, Maximum Battery, Maximum Performance 3가지가 있으며, 세부적으로 CPU Speed를 조절할 수도 있다.
  5. Standard는 기본적으로 동작하는 모드로 본래 노트북이 사용하는 CPU속도를 적용한다.
  6. Battery Maximum 모드는 배터리 최적화 모드로 느린 속도로 CPU를 동작시켜 발열을 줄여주고 배터리 사용량을 줄여 노트북을 보다 오랫동안 사용할 수 있도록 해준다. 하지만 CPU의 처리 속도가 떨어지므로 3D 게임과 같이 CPU의 연산을 많이 필요로 하는 소프트웨어 구동 시에는 느려지는 현상이 발생할 수 있다.
  7. Maximum Performance는 CPU의 속도를 최대로 하여 구동시키는 모드로 노트북의 최대 성능을 끌어낼 수 있지만 높은 발열로 인해 컴퓨터가 셧다운 될 수 있으며, 배터리 소모량 또한 가장 많아 노트북 사용 시간이 대폭 줄어든다. 따라서 순간적으로 빠른 작업을 요할 때 선택하는 것이 좋다.



기타 비디오 카드에 대한 설정 및 하드 디스크에 대한 설정도 할 수 있다. 이 소프트웨어를 잘 활용하면 동일한 배터리로 더욱더 노트북을 오랫동안 사용할 수 있거나 또는 동일한 노트북으로 보다 빠른 시간에 작업을 끝마칠 수도 있다. 하지만 Maximum Performance 상태를 오랫동안 유지하면 노트북에 무리를 줄 수 있으므로 필요한 작업만 하고 다시 다른 모드로 변경해 주는 것이 좋다.

참고로 일부 노트북은 판매가를 낮추기 위해 노트북(랩톱)용 CPU(Mobile)가 아닌 데스크톱 CPU를 사용한 경우가 있다. 이렇게 일반 데스크톱 CPU를 사용한 노트북(랩톱)의 경우 CPU 속도 조절 기능을 제공하지 않기 때문에 해당 소프트웨어를 정상적으로 사용할 수 없다

Posted by sjang


Leave a comment

자바스터디

참고 사이트

http://java.sun.com/docs/books/tutorial/
http://java.sun.com/j2se/1.5.0/docs/api/index.html
http://ant.apache.org/
http://lomboz.objectweb.org/

Posted by sjang


Leave a comment

http://blog.ilovelinux.org/2009/10/linux-epoll-listen.html
최신내용은 위 주소를 방문하세요.

=============================================================


리눅스 커널 2.6에서 공식지원하는 성능 좋은 소켓 트리거 epoll를 사용하다가 알게 된 것인데...

Listen 소켓을 edge로 등록해서 사용할 경우에, edge는 여러개가 동시에 오더라고 이벤트가

저장되지 않으므로(epoll man페이지에서 그렇다고 했다.) Listen 소켓은 level 트리거로 등록해야 한다.

또는, Non-blocking 소켓이므로 epoll에 등록하지 않고, accept()함수에서 이벤트가 발생하거나 할일이 없을 때, aceept()를 호출하는 방법도 있다.

Listen 소켓을 edge 트리거로 등록하여 접속 이벤트를 놓치는 버그가 발생하지 않도록 하자~~~

Posted by sjang


Leave a comment

마우스 키보드 공유 프로그램

리눅스와 윈도우를 함께 사용해야할 때, 두 대간에 마우스 키보드 왔다갔다 하기가 너무 번거롭다. synerg는 이러한 환경에 딱 맞는 솔루션이다.

클라이언트/서버 환경으로 마우스와 키보드 하나로, 두 시스템을 함께 사용하는 것이다.

http://synergy2.sf.net/

참고: 첨부파일은 shitf+space로 한영전환이 안되는 문제를 해결한 버전이다.



Posted by sjang


Leave a comment

SIGPIPE 처리 방법

Linux Server개발 초창기에 프로그램을 돌리다보면 다음과 같은 에러메시지를 뱉어내면서 서버가 돌아가실때가 있습니다.

"Program received signal SIGPIPE, Broken pipe."

이미 연결이 종료된 Client에 Send하려했을때 나오는 signal로 처리해주지 않으면 기본 동작은 "프로그램 종료"라서. 서버가 다운되게 됩니다.

하지만 서버의 경우 Client가 비정상적인 종료를 했을시 Broken pipe signal이 발생하고 Client의 종료를 서버에서 제어할 수 없기 때문에 해당 시그널을 무시하게 해주어야 합니다.

프로그램상에서 하는 방법은 다음과 같습니다.

#include signal.h
해주고 main 함수후에 시작부분에

signal(SIGPIPE, SIG_IGN);

코드를 넣어주면 됩니다. SIGPIPE 를 무시하라는 플래그를 셋팅해주는것이죠.

또 하나더..

위 서버 프로그램을 gdb로 돌릴때는 gdb에도 broken pipe 를 무시하는 옵션을 붙여줘야 합니다.

gdb 시작시

handle SIGPIPE nostop pass pass

라고 해주거나 , 해당 프로그램을 돌리는 계정의 홈디렉토리에 .gdbinit 라는 파일을 만들고
위 내용을 넣어주면 gdb실행시마다 기본으로 실행하게 됩니다.

Posted by sjang


Leave a comment