disassemble #1 - how to use gdb?

disassemble을 공부하면서 기본적인 사용법을 적어봅니다.

시작에 앞서..


먼저 assembly language Cpu의 제조사에 따라, 혹은 32bit / 64bit에 따라 그 모습을 달리 합니다.

기본적으로 32bit cpu는 알고 계시듯 메모리를 4GB까지 사용 할 수 있습니다.
2의 23승을 타나내며 값으로는 4,294,967,296 이고,
이는 cpu가 한번에 처리 할 수 있는 값의 범위이며 주소의 범위입니다.

이후 64bit cpu에서는 총 처리할 수 있는 값이 2의 64승으로 늘어났으며, 이는 16엑사바이트 입니다. 1엑사바이트는 1,048,576 테라바이트로 엄청난 숫자임을 이해 할 수 있습니다.

또한 어셈블리에서는 레지스터의 이름도 변하였고, 사용 할 수 있는 레지스터의 수도 증가하였습니다. 이를 감안하여 공부해야 합니다.

기본적인 코드 작성과 gdb 사용



위에 작성한 간단한 프로그램을 gcc를 이용해 컴파일 해줍니다.
(-g옵션을 이용해 디버깅 가능한 컴파일을 합니다.)
gcc -g first.c

그리고 gdb를 이용해 ./a.out를 실행시켜 줍니다.

[root@localhost assem]# gdb ./a.out
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-83.el6)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/assem/a.out...done.
(gdb)

아래 명령어를 통해 break point를 main 함수에 걸어주고, 프로그램을 실행 하도록 합니다.

(gdb) break main
Breakpoint 1 at 0x4004cc: file first.c, line 4.
(gdb) run
Starting program: /root/assem/a.out

Breakpoint 1, main () at first.c:4
4 int i = 0;
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.149.el6.x86_64

위의 run에서 현재 4번행 int i = 0;을 가르키고 있는 것을 확인 할 수 있습니다.
이상태로 disassemble해보도록 하겠습니다.

(gdb) disassemble
Dump of assembler code for function main:
     0x00000000004004c4 <+0>: push   rbp
     0x00000000004004c5 <+1>: mov    rbp,rsp
     0x00000000004004c8 <+4>: sub    rsp,0x10
=> 0x00000000004004cc <+8>: mov    DWORD PTR [rbp-0x4],0x0
     0x00000000004004d3 <+15>: jmp    0x4004e3 <main+31>
     0x00000000004004d5 <+17>: mov    edi,0x4005e8
     0x00000000004004da <+22>: call   0x4003b8 <puts@plt>
     0x00000000004004df <+27>: add    DWORD PTR [rbp-0x4],0x1
     0x00000000004004e3 <+31>: cmp    DWORD PTR [rbp-0x4],0x1
     0x00000000004004e7 <+35>: jle    0x4004d5 <main+17>
     0x00000000004004e9 <+37>: leave
     0x00000000004004ea <+38>: ret
End of assembler dump.

위와 같은 모습을 보실 수 있고, 다음에 실행될 위치를 (=>) 가르킵니다.

아래 명령어를 통해 현재 rip 레지스터(Instruction pointer register)를 통해 현재 위치를 확인 하겠습니다.

이 레지스터 RIP(EIP - 32bit)는 이후에 실행될 명령어의 위치를 가르키게 됩니다.

(gdb) info register rip
rip            0x4004cc 0x4004cc <main+8>

위를 통해 현재 rip의 주소는 0x4004cc 임을 확인 할 수 있고,

(gdb) x/i 0x4004cc    혹은 (gdb) x/i $rip 를 통해 현재 위치의 명령어를 확인 할 수 있습니다.

(gdb) x/i 0x4004cc
=> 0x4004cc <main+8>: mov    DWORD PTR [rbp-0x4],0x0

어셈블리어는 기본 명령 <목적지>, <근원지> 로 표현되며, 위 코드에선
명령 - mov
목적지 rbp-0x4
근원지 0x0
이 됩니다.

DWORD PTR은 4 바이트의 값을 읽어들인다는 뜻이 됩니다. (Int형 변수)

먼저 위 행을 실행하기 앞서 rbp에 어떤 값이 들어있는지 조사 해 보도록 하겠습니다.

이는 아래와 같이 표현합니다.

(gdb) x/xw $rbp-4
0x7fffffffe2bc: 0x00000000

현재 rbp의 주소는 0x7fffffffe2bc임을 확인 할 수 있고 내부에는 0이 값이 들어 있는 것을 확인 할 수 있습니다.

x/xw의 앞의 x 는 examine 명령어를 나타내며, 메모리 값을 조사 할 때 사용됩니다.

뒤의 x는 진법을 표시하며 아래 알파벳을 이용 할 수 있습니다.

o - 8진법
x - 16진법
u - Unsigned 10진법
t - 2진법

그리고 마지막 w는 내부 값을 조사 할 때 유효한 크기를 나타냅니다.

b - 단일 바이트
h - 2바이트 (하프워드)
w - 4바이트 (워드)
g - 8바이트 (자이언트)

다시 돌아와 mov명령어는 근원지에 있는 값을 목적지에 집어 넣으라는 이야기 입니다.

nexti를 통해 한 라인을 실행 하도록 하겠습니다.

(gdb) nexti
0x00000000004004d3 6 for(i=0; i<2; i++){
(gdb) x/i $rip
=> 0x4004d3 <main+15>: jmp    0x4004e3 <main+31>

명령어를 확인하기 앞서 앞에서 봤던 mov명령어가 실행된걸 확인 하면,

(gdb) x/xw $rbp-4
0x7fffffffe2bc: 0x00000000

0이 들어가 있는 것을 확인 할 수 있습니다.

이후 x/i $rip를 통해 다음 명령어를 확인 해 보겠습니다.

jmp는 jump명령어로 0x4004e3번지로 jump하라는 명령입니다.

(gdb) x/i 0x4004e3 을 통해 번지를 조사하면
   0x4004e3 <main+31>: cmp    DWORD PTR [rbp-0x4],0x1
위 명령어로 이동 하라는 것을 확인 할 수 있습니다.

(gdb) nexti
0x00000000004004e3 6 for(i=0; i<2; i++){
(gdb) x/i $rip
=> 0x4004e3 <main+31>: cmp    DWORD PTR [rbp-0x4],0x1

cmp는 비교 명령어 입니다. rbp-0x4에 집어넣엇던

0이라는 값과, for문에서 집어넣었던 i<2라는 값을 비교합니다. (작거나 같은지)

(gdb) nexti
0x00000000004004e7 6 for(i=0; i<2; i++){
(gdb) x/i $rip
=> 0x4004e7 <main+35>: jle    0x4004d5 <main+17>

jle는 작거나 같은경우 jump하라는 명령어로 이 경우엔 윗 줄에서 비교했던
$rbp-4가 1보다 작거나 같으면 17라인으로 jump 하라는 명령입니다.

이 경우 $rbp-4의 값이 0이었으므로 17라인으로 이동하게 될 것입니다.
그렇지 않다면
이 코드에서는 점프 없이 다음 명령어로 통과하게 되어 for문을 빠져나오게 됩니다.

우선 다음으로 넘어가 보도록 하겠습니다.

(gdb) nexti
7 printf("Hello\n");
(gdb) x/i $rip
=> 0x4004d5 <main+17>: mov    edi,0x4005e8

예상대로 17라인으로 이동하는 것을 확인 할 수 있습니다.

여기선 EDI 레지스터에 0x4005e8 이라는 값을 집어넣으라는 이야기를 하고 있는데,

EDI(Extended Destination Index) register는 복사 시에 목적지의 주소가 저장되는 index입니다.

0x4005e8의 값을 확인 해 보기 위해 아래 명령어를 확인 해보도록 하겠습니다.

(gdb) x/xw 0x4005e8
0x4005e8 <__dso_handle+8>: 0x6c6c6548

(gdb) x/6b 0x4005e8
0x4005e8 <__dso_handle+8>: 0x48 0x65 0x6c 0x6c 0x6f 0x00

(gdb) x/6db 0x4005e8
0x4005e8 <__dso_handle+8>: 72 101 108 108 111

먼저 첫 번째 실행 결과로 0x6c6c6548 이란 값을 확인 할 수 있습니다.

위를 바이트 단위로 끊어 보게 되면 두 번째 출력값을 확인 할 수 있는데, 이는 꽤나 눈에 익은 HEX값입니다. 다음으로 세번째 출력 x/6db를 통해 6개의 바이트를 10진수로 꺼내 보면

ASCII(아스키코드)값의 범위에 들어가는 것을 보실 수 있습니다.

이를 아래 명령어를 통해 출력해보면

(gdb) x/6c 0x4005e8
0x4005e8 <__dso_handle+8>:   72 'H'   101 'e'    108 'l'   108 'l'   111 'o'   0 '\000'

각각 H e l l o \0 이란 것을 확인 할 수 있습니다.

더 보기좋게 하기위해 아래와 같은 출력 방법이 가능합니다.

x/s 0x4005e8

(gdb) x/s 0x4005e8
0x4005e8 <__dso_handle+8>: "Hello"


그런데 다시 위의 출력값으로 돌아가보면,

(gdb) x/xw 0x4005e8
0x4005e8 <__dso_handle+8>: 0x6c6c6548

(gdb) x/6b 0x4005e8
0x4005e8 <__dso_handle+8>: 0x48 0x65 0x6c 0x6c 0x6f 0x00

여기서 바이트의 역순(Byte-reversal)이 일어난 것을 확인 할 수 있습니다.

이는 프로세서가 값을 little-endian 바이트 순서로 저장하기 때문이며, 꺼내올때 역순으로 꺼내오기 때문입니다. 이는 cpu가 저장공간에 IP address를 저장할 때에도 같은 현상을 보실 수 있습니다.

이후 진행되는 나머지 코드들은 위 내용의 반복입니다.





linux - If server has multiple interface that specify default gateway device. (Red Hat Enterprise Linux 5, 6)

레드햇 리눅스 에서 서버 이더넷 포트에 다수의 게이트웨이가 있어 route시 default gateway가 재대로 잡히지 않는 현상이 있습니다.

위와 같은 현상이 있다면 아래와 같이 설정 할 수 있습니다.

- Resolution


 # vi /etc/sysconfig/network

위 명령어를 실행 한 뒤 아래 내용을 추가해줍니다.

 GATEWAYDEV=ethX

ethX = 디폴트 게이트웨이로 설정할 이더넷 포트

python - pxssh를 이용한 ssh connect & send command

pxssh를 이용하면 ssh를 이용해 linux에 접속하여 직접 command를 날릴 수 있고, 반환값도 받아 올 수 있습니다.

먼저 pxssh를 이용하기위해 모듈 pexpect를 설치해줍니다.

# wget https://pypi.python.org/packages/source/p/pexpect/pexpect-4.0.1.tar.gz#md5=056df81e6ca7081f1015b4b147b977b7

# tar xvf pexpect-4.0.1.tar.gz

# cd pexpect-4.0.1.tar.gz

# python setup.py install

먼저 모듈을 아래와 같이 로드해줍니다.

from pexpect import pxssh

현재 파이썬 3.x버전을 사용하고 있으며, 간혹 책이나 튜토리얼을 보게되면

import pxssh 와 같이 선언하는 문구를 보실 수 있습니다.

그러나 위와 같이 선언시 import하지 못해 에러가 발생합니다.

s = pxssh.pxssh()를 통해 변수를 초기화 해 준 뒤 아래의 함수들을 이용하여 로그인 및 커맨드를 실행합니다.

s.login(Domain, ID, Password) - 로그인 관련 메소드로 해당 도메인에 해당 아이디와
 패스워드를 이용해 로그인 합니다.

s.sendline(Command) - 명령어를 실행하는 부분으로 Command에 입력된 명령어를 실행합니다.

s.prompt() - 실행된 명령어의 실행(return되는) 값을 받기 위해 사용합니다.

s.before.decode() - s.before에 실행된 명령어를 가지고 있고, 이를 decode()하여 출력합니다.


위와 같은 코드를 완성하였습니다.

Line 4 - 127.0.0.1 도메인으로 root/123456 으로 로그인을 시도합니다.
(로그인 관련 리턴값을 받아 올 수 있습니다.)
Line 6 - uname -v 명령어를 실행합니다.
Line 8 - 받아온 값을 출력합니다.

실행 결과는 아래와 같습니다.

----------------------------------------------------------------
# python3 pxssh.py 
uname -v
#1 SMP Tue Nov 11 17:57:25 UTC 2014
----------------------------------------------------------------



linux - Dell서버 Ethernet device name em -> eth 변경

dell서버에서 centos나 redhat linux설치 시 ethernet 디바이스 이름이 아래와 같이 em으로 등록 되어 있는것을 볼 수 있습니다.

$ ifconfig

em1      Link encap:Ethernet  HWaddr 20:47:47:8B:72:2C  
            UP BROADCAST RUNNING SLAVE MULTICAST  MTU:1500  Metric:1
            RX packets:13287407 errors:0 dropped:0 overruns:0 frame:0
            TX packets:3518085 errors:0 dropped:0 overruns:0 carrier:0
            collisions:0 txqueuelen:1000 
            RX bytes:3979015280 (3.7 GiB)  TX bytes:1456833747 (1.3 GiB)
            Interrupt:41



$ cd /etc/sysconfig/network-scripts

위 경로로 이동해 보시면 디바이스 name이 em으로 되어있는 것을 보실 수 있습니다.

ifcfg-em1
ifcfg-em2
...


먼저 디바이스 name을 바꾸기 위해 패키지를 하나 삭제해야합니다.

rpm 명령어를 통해 패키지를 검색합니다.

$ rpm -qa | grep biosdevname
biosdevname-0.4.1-3.el6.x86_64

검색된 패키지를 rpm 명령어를 통해 삭제해 줍니다.

$ rpm -e biosdevname-0.4.1-3.el6.x86_64

위 명령어를 통해 패키지를 삭제 한 뒤 아래 파일을 수정해줍니다.

$ vi /etc/udev/rules.d/70-persistent-net.rules

위 파일이 존재하지 않는다면 추가 해 줘야 하는데, 첨부파일을 다운받아 수정하셔도 됩니다.

SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="xx:xx:xx:xx:xx:xx", ATTR{type}=="1", KERNEL=="*", NAME="em1"

위 내용을 아래와 같이 수정합니다.

SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="xx:xx:xx:xx:xx:xx", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"

** xx:xx:xx:xx:xx:xx부분엔 포트의 mac-address를 넣어 주시면 됩니다. (ifcfg-emX 파일 참고)

em1 포트는 eth0 포트와 같습니다.

수정 하신 뒤 아래 폴더로 이동합니다.

$ cd /etc/sysconfig/network-scripts

그리고 ifcfg-em(숫자) 를 ifcfg-eth(숫자-1)로 수정 해 줍니다.
ex) ifcfg-em1 -> ifcfg-eth0

그리고 파일 내부를 수정해줍니다.
DEVICE=em1 -> DEVICE=eth0

$ init 6를 통해 시스템을 리부팅 시켜줍니다.


linux - ntpd client 간단 설정 및 트러블 슈팅

1. ntpd 설치

#yum -y install ntp
위 명령어를 통해 ntp를 설치해 줍니다.

2. ntpd clinet 서버 주소 입력

#vi /etc/ntp.conf
위 파일을 실행 시킨 후 아래의 빨간색 부분에

server (ntp server hostname) 을 입력해 줍니다.
(아래의 ntp.postech.ac.kr은 포항공대의 ntp서버입니다.)


     20 # Use public servers from the pool.ntp.org project.
     21 # Please consider joining the pool (http://www.pool.ntp.org/join.html).
     22 server ntp.postech.ac.kr
     23 #server 0.rhel.pool.ntp.org
     24 #server 1.rhel.pool.ntp.org
     25 #server 2.rhel.pool.ntp.org
     26
     27 #broadcast 192.168.1.255 autokey        # broadcast server
     28 #broadcastclient                        # broadcast client
     29 #broadcast 224.0.1.1 autokey            # multicast server
     30 #multicastclient 224.0.1.1              # multicast client
     31 #manycastserver 239.255.254.254         # manycast server
     32 #manycastclient 239.255.254.254 autokey # manycast client

3. ntpd를 재시작 해줍니다.

#service ntpd restart

4. ntpd 상태 확인

#ntpq -pn을 통해 아래와같이 ntp의 상태를 확인 할 수 있습니다.
poll이 갱신 타임으로 ntp.conf에서 설정 가능 합니다.
     remote           refid          st t when  poll  reach  delay    offset   jitter
==========================================================
*141.223.182.106    .GPS.         1 u   58    64    377   8.643  -63.180  92.177





5. ntp 서버 통신 오류

#ntpd -pn

 remote        refid           st t when poll reach   delay   offset  jitter
=====================================================
 1.1.1.1         .INIT.          16 u    -   64    0    0.000    0.000   0.000

 no server suitable for synchronization found

위와 같이 통신이 안될 때 확실히 통신이 안되는지 아래 명령어를 통해 확인합니다.

#ntpd -d 1.1.1.1
아래와 같이

transmit(1.1.1.1)
transmit(1.1.1.1)
transmit(1.1.1.1)
transmit(1.1.1.1)
transmit(1.1.1.1)

전송만 하고 리시브 받지 못하면 ntp서버가 열려있지 않은 겁니다.

transmit(141.223.182.106)
receive(141.223.182.106)
transmit(141.223.182.106)
receive(141.223.182.106)
transmit(141.223.182.106)
receive(141.223.182.106)
transmit(141.223.182.106)
receive(141.223.182.106)
transmit(141.223.182.106)
server 141.223.182.106, port 123

정상적인 서버는 위와같이 receive 받습니다.

6. ntp time 강제로 맞추기

 ㄱ. ntpd 실행 상태에서 시간 맞추기
 
  # ntpdate -u 141.223.182.106
  13 Oct 14:59:06 ntpdate[51466]: adjust time server 141.223.182.106 offset 0.005536 sec

 위 명령어 -u는 ntpd 소켓인 123번 소켓이 아닌 다른 소켓을 사용하여 ntp서버 time을 받아옵니다.

 ㄴ. ntpd 서버 종료 후 시간 맞추기

  #service ntpd stop
  #ntpdate -b 141.223.182.106
  #service ntpd start

  위와 같은 방법을 사용하면 ntp서버를 멈춘 뒤 123번 포트를 이용해 date를 받아옵니다.

Python make port scanner(use nmap) #3 - make port scanner (파이썬 포트스캐너 만들기 #3 - port scanner)

앞서 두 과정을 통해 optparse의 사용과 nmap을 설치하였습니다.
이제 파이썬과 nmap 통해 port scanner를 제작 해보도록 하겠습니다.

참조 - 해커의언어, 치명적 파이썬 / TJ오코너

1. optparse 제작

먼저 optparse를 통해 아래와같은 소스를 제작해 보도록 하겠습니다.


-H와 -p -A 옵션을 통해 각각 아래의 기능을 구현합니다.

-H = Host name (ex. 127.0.0.1)
-p = port number (ex. 22)
-A = 직접 명시해 놓은 port (21,22,23,25,42,53,70,79,80,88,110,118,156,161,220,8080)을 스캐닝 합니다.

line 15: 15번 라인을 통해 -H옵션이 없거나 -p나 -A옵션중 하나가 쓰이지 않았다면 프로그램을 종료하도록 처리합니다.

line 19, 22: 19번 라인과 22번 라인을 통해 각 각 -p옵션과 -A옵션을 처리합니다.
-A옵션이 있을 때엔 위에 port변수에 명시한 port들을 scanning하는 분기를 처리하고
-A옵션이 없고 -p옵션이 있을 때에는 -p옵션에 명시한 port들을 scanning하는 분기를 처리합니다.

2. portscanner 제작

nmap을 통해 아래와 같은 함수를 제작해 줍니다.


line 4: 4번 라인을 통해 nmap.PortScanner를 load해 줍니다.
line 5: 5번 라인을 통해 함수 호출때 입력받은 인자(ip주소, 포트넘버)를 load 합니다.
line 6: 6번 라인을 통해 nmScan을 통해 현재 상태 state값을 받아옵니다.
line 7: 7번 라인을 통해 값을 print 해 줍니다.

3. portscanner 완성 및 실행

위에 제작한 1, 2번을 아래와 같이 합쳐줍니다.


27, 32번 line의 if else문도 수정 합니다.


------------------------------------------실행 모습---------------------------------------
# python3 TCPportscanner -H 127.0.0.1 -p 22
 [*] 127.0.0.1 tcp/22 open


# python3 TCPportscanner -H 127.0.0.1 -A
 [*] 127.0.0.1 tcp/21 closed
 [*] 127.0.0.1 tcp/22 open
 [*] 127.0.0.1 tcp/23 open
 [*] 127.0.0.1 tcp/25 closed
 [*] 127.0.0.1 tcp/42 closed
 [*] 127.0.0.1 tcp/53 closed
 [*] 127.0.0.1 tcp/70 closed
 [*] 127.0.0.1 tcp/79 closed
 [*] 127.0.0.1 tcp/80 closed
 [*] 127.0.0.1 tcp/88 closed
 [*] 127.0.0.1 tcp/110 closed
 [*] 127.0.0.1 tcp/118 closed
 [*] 127.0.0.1 tcp/156 closed
 [*] 127.0.0.1 tcp/161 closed
 [*] 127.0.0.1 tcp/220 closed
 [*] 127.0.0.1 tcp/8080 closed


( httpd 80번 포트 서비스 오픈 후 실행)
# service httpd start
Starting httpd: httpd: apr_sockaddr_info_get() failed for 500009674769
httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName
                                                           [  OK  ]

# python3 TCPportscanner -H 127.0.0.1 -A
 [*] 127.0.0.1 tcp/21 closed
 [*] 127.0.0.1 tcp/22 open
 [*] 127.0.0.1 tcp/23 open
 [*] 127.0.0.1 tcp/25 closed
 [*] 127.0.0.1 tcp/42 closed
 [*] 127.0.0.1 tcp/53 closed
 [*] 127.0.0.1 tcp/70 closed
 [*] 127.0.0.1 tcp/79 closed
 [*] 127.0.0.1 tcp/80 open
 [*] 127.0.0.1 tcp/88 closed
 [*] 127.0.0.1 tcp/110 closed
 [*] 127.0.0.1 tcp/118 closed
 [*] 127.0.0.1 tcp/156 closed
 [*] 127.0.0.1 tcp/161 closed
 [*] 127.0.0.1 tcp/220 closed
 [*] 127.0.0.1 tcp/8080 closed
------------------------------------------실행 모습---------------------------------------




Python make port scanner(use nmap) #2 - install nmap (파이썬 포트스캐너 만들기 #2 - nmap)

파이썬 포트스캐너 두 번째로 nmap과 nmap 라이브러리를 설치하도록 하겠습니다.

먼저 nmap을 설치하기위해 아래 명령어를 실행합니다.

# yum install -y nmap 

설치가 완료되어지면 아래 명령어를 통해 파이썬용 nmap 라이브러리를 다운받습니다.

# wget http://xael.org/pages/python-nmap-0.4.3.tar.gz 

다운받은 nmap의 압축을 풀어줍니다.

# tar -xvf python-nmap-0.4.3.tar.gz

압축 푼 python-nmap-0.4.3 디렉토리에 들어갑니다.

# cd python-nmap-0.4.3 

아래 명령어를 통해 라이브러리를 install 해줍니다.

# python setup.py install

위 과정을 통해 nmap의 설치화 python에서 nmap을 사용 할 수 있는 라이브러리의
준비가 완료되어집니다.

Python make port scanner(use nmap) #1 - optparse (파이썬 포트스캐너 만들기 #1 - optparse)

파이썬을 이용한 포트스캐너 제작에 앞서 python optparse 모듈에대해 알아보겠습니다.

optparse는 커맨드 라인 프로그램 실행에 이용된 option값을 parsing해주는 모듈입니다.

아래와 같은 커맨드를 가정해 보겠습니다.

python <%program> <%option> <%values>
python optparse.py -f TCPportscanner

위의 커맨드를 통해 program을 실행시킬때 option값을 통해 values를 가져오는 방식입니다.
optparse.py를 실행시킬 때 -f옵션을 통해 filename을 value로 가져오는 방식으로, 프로그램
내에서는 TCPportscanner의 파일명(경로)를 가져오게 됩니다.

아래 소스를 살펴보겠습니다.

line 3: parser = optarse.OptionParser() 를 통해 optparse모듈을 로드합니다.

line 4: parser.add_option()을 통해 받아올 옵션값에대한 정보를 가져옵니다.
a. "-f", "--file"는 사용할 옵션의 형태를 나타냅니다. 이를 통해 프로그램을 실행할 때
<%program> -f <%values>혹은 <%program> --file <%values>형태를 사용 할 수 있습니다.
b. dest="filename"을 통해 이후 변수에 값을 가져올 때 사용 할 도착지 이름입니다.
c. help="File name"을 통해 <%program> -h 명령어를 쳤을 때 불러올 help의 내용을 입력합니다.
d. metavar="FILE"을 통해 meta type을 정의해줍니다.

line 5: parser.add_option()
a. '-p'를 통해 옵션의 형태를 취합니다.
b. dest='port'를 통해 변수에 가져올 도착지 이름을 정합니다.
c. type='int'를 통해 변수의 type을 정의해 줍니다.
d.help=''를 통해 -h명령어에 대한 description을 정의합니다.

line 6: action='store_true', default=False
위 두 옵션은 Flag값을 정의할 때 쓰입니다.
기본적으로 parser.add_options()을 5번 라인과 같은 형태를 취했을 때엔
<%program> -p <%values> 형식으로 사용되어 지지만, flag형태를 취하면
<%program> -a 만으로도 불러 올 수 있고 -a옵션이 활성화되면 Flag가 True로 변하게 됩니다.

즉 action='store_true'를 통해 옵션을 불러왔을때 default=False로 설정되어있던 값을 True로 가져오게 됩니다.

line 8: (options, args) = parser.parse_args()
 parsing한 옵션 값들을 변수로 불러오기 위해 options에 집어넣어줍니다.

line 10, 11, 12: 기본적으로 option을 사용하지 않으면 값에 None가 들어있게 됩니다.
만약 필수 옵션이라면 if문을 통해 그 옵션값이 None일 때, 프로그램을 종료 시킬 수 있습니다.

line 14, 15, 16: 각각 받아온 옵션값을 변수에 저장해 줍니다.

line 18. 19. 20: 각각 받아온 옵션값을 출력합니다.

--------------------------------------------- 실행 모습------------------
# python3 optparse -f TCPportscanner
None
False
TCPportscanner



# python3 optparse -f TCPportscanner -p 22
22
False
TCPportscanner



# python3 optparse -f TCPportscanner -p 22 -a
22
True
TCPportscanner



#python3 optparse -h
Usage: optparse [options]

Options:
  -h, --help            show this help message and exit
  -f FILE, --file=FILE  File name
  -p PORT               input port number

  -a                    flag tuto
--------------------------------------------- 실행 모습------------------

android setImage failed (사진을 못 가져올 때)

갤러리에서 사진을 선택할 때 사진을 못 가져오는 현상이 발생하면 아래 두 가지 경우를 생각 할 수 있습니다.

1. Permission Denial

java.lang.SecurityException: Permission Denial: reading 
com.android.providers.media.MediaProvider uri 
content://media/external/images/media/38498 from pid=27232, uid=10472 requires 
android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()

이 경우는 External storage에서 URI를 가져올 때 권한에 막혀 가져오지 못하는 경우입니다.
위와 같은 경우는 Manifest에 아래와 같이 권한 설정을 해주면 쉽게 가져올 수 있습니다.

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>


2. 이미지 용량 초과

 삼성 핸드폰의 경우 'Input agif image larger than 30MB.' 라는 로그 메세지를 보실 수 있
습니다. 일정 용량 이상의 사진파일은 불러오지 못하므로, setImageUri(uri)를 아래와 같이
BitmapFactory를 이용해 이미지의 size를 조정해주시면 불러 올 수 있습니다.

uri = data.getData();
try {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 2;
    Bitmap myBitmap = BitmapFactory.decodeStream(view.getContext().getContentResolver().openInputStream(uri), null, options);
    selectedImageView.setImageBitmap(myBitmap);
} catch(Exception e){
    e.getStackTrace();
}

Application windows are expected to have a root view controller at the end of application launch

에러 코드

Xcode 7 iOS9에서 발생
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException'reason : 'Application windows are expected to have a root view controller at the end of application launch'


원인

Xcode 7부터 앱 시작전에 root view controller를 설정해 주어야 합니다.


해결

-  ( BOOL ) application : ( UIApplication  * ) Application  didFinishLaunchingWithOptions : ( NSDictionary * ) launchOptions {
    // 윈도우 초기화
    self . window  =  [[ UIWindow  alloc ]  initWithFrame : [ UIScreen  MainScreen ]  bounds ]];
    self . window . rootViewController  =  [ UIViewController  new ];
    [ self . window  makeKeyAndVisible ];

    return  YES ;
}



python django 설치

django의 설치를 위해 아래 주소에서 tar.gz을 다운받습니다.

https://www.djangoproject.com/

다운받은 Django-1.8.4.tar.gz의 압축을 해제하면 아래와 같은 모습을 보실 수 있습니다.
























위 폴더의 setup.py를 아래와 같이 실행시켜줍니다.































setup.py install을 실행하면 아래와같이 설치가 진행, 완료됩니다.






























설치 완료된 django 프레임워크의 버전은 아래와 같이 django.get_version()을 통해 확인 할 수 있습니다.







App Transport Security

iOS9 혹은 OS X 10.11이상에서 유효한 기능이며, 어플이나 웹서비스 간의 안전한 연결을 위해 사용할 수 있습니다.

ATS가 활성화 되면 HTTP통신을 할 수 없습니다. 또한 Apple에서 권장하는 요구 사항을 충족하지 않는 연결은 강제로 연결 실패 처리 됩니다.



실제 에러 메시지

Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSErrorFailingURLStringKey=에러가 발생한 URL, NSErrorFailingURLKey=에러가 발생한 URL, NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection., NSUnderlyingError=0x14eae740 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSErrorFailingURLKey=에러가 발생한 URL, NSErrorFailingURLStringKey=에러가 발생한 URL, NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.}}}




필요조건

  • TLS버전 1.2 이상
  • 연결시 사용할수 있는 암호화스위트(암호화 알고리즘의 조합)는 다음 리스트로 제한
    • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
    • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
    • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
    • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
    • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
    • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
    • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
    • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
  • 서버인증서에 요구되는 조건
    • SHA256 이상의 지문
    • 2048 비트 이상의 RSA 키 또는 256 비트 이상의 Elliptic-Curve(ECC)키
  • 잘못된 인증서를 사용하면 강제로 실패되어, 연결할 수 없음



필요조건을 만족시킬 수 없는 경우

Info.plist에 특정 키와 값을 추가하면 ATS를 비활성화하거나 일부 동작을 변경할 수 있습니다.


ATS를 비활성화 (비추천)
<key> NSAppTransportSecurity </ key>
<dict>
    <key> NSAllowsArbitraryLoads </ key>
    <true />
</ dict>


기본적으로 ATS를 활성화 하고 ATS의 대상으로 하지 않는 도메일을 Info.plist에 기재
<key> NSAppTransportSecurity </ key>
<dict>
    <key> NSExceptionDomains </ key>
    <dict>
        <key> 예외처리할 도메인 </ key>
        <dict>
            <key> NSTemporaryExceptionAllowsInsecureHTTPLoads </ key>
            <true />
        </ dict>
    </ dict>
</ dict>


기본적으로 ATS를 무효로하고, ATS의 대상으로하는 도메인을 Info.plist에 기재
<key> NSAppTransportSecurity </ key>
<dict>
    <key> NSAllowsArbitraryLoads </ key>
    <true />
    <key> NSExceptionDomains </ key>
    <dict>
        <key> 예외처리할 도메인 </ key>
        <dict>
            <key> NSTemporaryExceptionAllowsInsecureHTTPLoads </ key>
            <false />
        </ dict>
    </ dict>
</ dict>


ATS의 요구사항을 낮출 설정을 Info.plist에 기재
<key> NSAppTransportSecurity </ key>
<dict>
    <key> NSExceptionDomains </ key>
    <dict>
        <key> 도메인 </ key>
        <dict>
            <key> NSTemporaryExceptionMinimumTLSVersion </ key>
            <string> TLSv1.1 </ string>
            <key> NSTemporaryExceptionRequiresForwardSecrecy </ key>
            <false />
        </ dict>
    </ dict>
</ dict>






Red-Hat 계열 Linux에서 Tomcat Service Setting

Install 및 Setting 전 확인 사항

  1. Root계정 권한 획득
  2. Tomcat 다운로드 후 압축 해제 상태


기본적으로 tomcat install은 패키지 설치가 아닌 apache tomcat을 다운받아서 압축을 푸는 개념으로 모든 설정파일과 service 시작 daemon파일이 tomcat 폴더에 들어있어 tomcat폴더의 bin 폴더에 들어가면 startup.sh와 shutdown.sh를 볼 수 있습니다. 이를 service 명령어로 올리고 내릴 수 있도록 설정하고 또한 리눅스 실행과 동시에 startup하도록 chkconfig에 등록 하도록 하겠습니다.

Where is Servie file


<Red-Hat/CentOS>

# pwd

위의 명령어를 통해 우선 startup파일과 shutdown파일의 위치를 확인 합니다.


Create Service shell script file

# vi /etc/rc.d/init.d/tomcat

위 커맨드를 실행 한 뒤 dhcp server를 configure해줍니다.


아래와 같이 Shell script를 작성 해 줍니다.




  1. 6~7번 line을 통해 chkconfig에 등록 할 수 있도록 해줍니다.
  2. 8번 line의 변수 TOMCAT_HOME에 tomcat폴더의 경로를 지정해줍니다.
  3. 11번 line 부터 case명령어를 통해 service {start|stop|restart}시의 기능을 부여합니다.
(start)시 startup.sh실행 (stop)시 shutdown.sh실행 (restart)시 stop, start 반복



add chkconfig

#chkconfig --add tomcat 을 설정합니다.
#chkconfig tomcat on 을 해 linux 시작 시 실행되도록 설정합니다.
#chkconfig --level 2345 tomcat on 커맨드를 통해 Run level별로 지정 해 줄 수 있습니다.
#chkconfig --list를 통해 확인합니다.




Service start

# /etc/init.d/tomcat start
# /etc/init.d/tomcat stop


# service tomcat start
# service tomcat stop


Android dynamic change image resource (안드로이드 동적 이미지 변경)

안드로이드 소스코드 내에서의 동적 이미지 변경 방법입니다.

setImageResource(getApplication().getResources().getIdentifier(String name, String defType, String defPackage));

위와같은 방식으로 가져오며, 아래는 소스코드의 예 입니다.

imageView image= (ImageView)findViewById(R.id.test_image);
image.setImageResource(getApplication().getResources().getIdentifier("ic_launcher", "mipmap", "com.testcode.testproject"));

이런 방식으로 소스코드 내에서 이미지를 변경 할 수 있습니다.

Android error: resource entry is already defined

안드로이드에서 error: resource entry name.png is already defined

라는 문구가 뜨면

이미 올라가있던 jpg파일이 등록된 후 png파일이 올라와서 리소스에 중복되어있는 경우입니다.

안드로이드 프로젝트 build -> rebuild project를 하시면 손쉽게 해결 할 수 있습니다.

Python socket programming #4 - multiprocessing #1

Python에서 thread는 GIL(Global Interpreter Lock)을 따르게 됩니다.
간단하게 설명하면 보통은 다수의 쓰레드가 작동할 때에 아래와 같은 모델을 상상하게 됩니다.

하지만 GIL에 의해서 python은 한 Thread씩 Lock이 걸리는게 아니라 전체에 걸리게 되면서 여러개의 Thread가 Single Processor에서 동작 하는 것 처럼 동작하게 됩니다.



프로그램을 통해 살펴보면

위는 한 개의 Thread를 동작시켜 총 작업 시간을 출력한 프로그램입니다.
100000000의 숫자를 하나씩 빼면서 while문을 돌리는 간단한 프로그램입니다.
출력 결과는 아래와 같습니다.

---------------------------------------------------
Starting Thread_1
Thread_1 의 작업 시간 8
Exiting Thread_1

Exiting Main Thread
총 작업 시간 8
---------------------------------------------------

또 다른 프로그램을 살펴보면

위는 두 개의 Thread를 동작시켜 총 작업 시간을 출력한 프로그램입니다.
기본적으로 생각했을 때엔 위에서 살펴본 하나의 Thread의 작업 시간인 8초와
동일한 시간을 생각 해 볼 수 있습니다. 하지만 결과는 아래와 같습니다.

---------------------------------------------------
Starting Thread_1
Starting Thread_2
Thread_2 의 작업 시간 15
Exiting Thread_2

Thread_1 의 작업 시간 16
Exiting Thread_1

Exiting Main Thread
총 작업 시간 16
---------------------------------------------------

생각했던 것과는 다르게 하나의 Thread의 작업 시간 8초의 두 배인 16초가 출력 되는 것을 보실 수 있습니다.

위와 같은 이유로 python에서는 thread보단 multiprocessing이 권장되어집니다.

1. Multiprocessing

python에서 사용하는 multiprocessing은 fork()와 같게 생각하시면 됩니다.
하나 이상의 자식 process를 생성하여 이를 병렬구조로 처리하는 것을 지칭합니다.

import multiprocessing
위와같이 모듈을 불러와 사용 할 수 있습니다.

2. Pool

p = Pool(n)
위의 Pool(n)을 통해 미리 process를 생성 할 수 있게 됩니다.

p.map(function, values)
위의 Pool.map을 통해 각 process들이 함수를 동작 시키게 할 수 있습니다.

multiprocessing의 pool을 이용한 예제를 통해 살펴보겠습니다.

위의 예제는 pool을 통해 3개의 process를 생성하고, f(x)함수를 불러와 1초씩 함수에서 대기하게 됩니다. 결론적으로 3개의 process가 10개의 값을 연산하려면 아래와 같이 총 4초가 걸리게 됩니다.

프로세서     값        연산시간      누적 연산시간
process 1 -> 0 -------- 1초  -------- 1초
process 2 -> 1 -------- 1초  -------- 1초
process 3 -> 2 -------- 1초  -------- 1초
------------------------------------------------------
process 1 -> 3 -------- 1초  -------- 2초
process 2 -> 4 -------- 1초  -------- 2초
process 3 -> 5 -------- 1초  -------- 2초
------------------------------------------------------
process 1 -> 6 -------- 1초  -------- 3초
process 2 -> 7 -------- 1초  -------- 3초
process 3 -> 8 -------- 1초  -------- 3초
------------------------------------------------------
process 1 -> 9 -------- 1초  -------- 4초


process를 4개로 늘리거나, range를 (0,9)로 수정한다면 누적 연산시간이 3초가 걸리는 것을
확인 하실 수 있습니다.

아래는 출력 결과입니다.

값 0 에 대한 작업 Pid =  3712
값 1 에 대한 작업 Pid =  3740
값 2 에 대한 작업 Pid =  2568
값 3 에 대한 작업 Pid =  3712
값 4 에 대한 작업 Pid =  3740
값 5 에 대한 작업 Pid =  2568
값 6 에 대한 작업 Pid =  3712
값 7 에 대한 작업 Pid =  3740
값 8 에 대한 작업 Pid =  2568
값 9 에 대한 작업 Pid =  3712
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
총 작업 시간 4

Collection Framework(Java의 자료구조)

1.  Collection Framework
JDK 1.2이전 까지는 collection class인 Vector, Stack, Hashtable, Properties등을 사용 했으나, 이후 collection framework가 생기면서 재사용성이 높은 코드를 사용 할 수 있게 되었습니다. 

이후 collection class는 남아 있지만 


2. 대표 인터페이스
Collection Framework에는 크게 세 인터페이스로 나누어지며 특징은 다음과 같습니다.


  1. List - 중복이 가능한 순서를 기억하는 데이터 집합
  2. Set - 중복이 불가능하며 순서를 기억하지 않는 데이터 집합
  3. Map - 키와 값을 가지고 순서는 기억하지 않으며 키는 중복이 불가능하고 값은 중복이 가능한 데이터 집합







px, dp, dip, sp의 차이

dp (Density-independent Pixels)
160dpi화면을 기준으로 하며, 1dp1px과 거이 동일합니다.
고밀도 화면에서 실행할 경우 1dp를 그리는데 사용되는 픽셀의 수는 화면의 dpi 따라 적절히 조정되며, 마찬가지로 저밀도일 때 1dp의 화소 수는 축소됩니다.
px단위 대신에 dp단위를 사용하면 밀도가 다른 화면에서도 UI요소들의 일관성을 제공합니다. 

dip (Density-Independent Pixels)
dip는 초기버전에서 사용했지만 지금은 dp로 축약되었습니다.
 
sp (Scale-independent Pixels)
spdp단위와 같지만 사용자의 폰트사이즈 설정에 의해 조절됩니다.
sp는 글꼴크기를 지정 할 때 사용하는 것이 좋습니다.
 
pt (point)
1/72인치 에 해당됩니다.
 
px (pixels)
실제 화면의 픽셀에 해당합니다.
각 디바이스는 인치 당 픽셀수가 다르고 화면에서 사용 가능한 픽셀 수가 많거나 적을 수 있습니다. 
 
mm (Millimeters)
화면의 실제 크기를 기준으로 합니다.
 
in (Inches)
화면의 실제 크기를 기준으로 합니다.















Python socket programming #3 - MultiThreading (Threading module)

2. threading


두 번째로 threading 모듈은 thread 클래스를 상속받아 사용하는 모듈입니다.

클래스가 threading.Thread를 상속받아 사용하게 됩니다.

java와 마찬가지로 run 메소드를 오버라이드 하여 각 각 선언된 클래스를 통해

Class_name.start()를 작동시키면 run 메소드가 작동하게 됩니다.

위의 코드를 보면

class myThread (threading.thread):를 통해 클래스를 선언 한 뒤

생성자를 통해 thread의 name과 delay time을 인자로 받습니다.

이 후 thread1.start()를 통해 run 메소드를 작동시킵니다.

run 메소듣 내부에서는 print_count함수를 호출하여 5회 각 각 1초와 2초의 딜레이를 부여해 내용을 출력합니다.

아래는 출력 내용입니다.

Starting Thread_1
Exiting Main Thread
Starting Thread_2
Thread_1: 5
Thread_2: 5Thread_1: 4

Thread_1: 3
Thread_2: 4
Thread_1: 2
Thread_1: 1
Exiting Thread_1
Thread_2: 3
Thread_2: 2
Thread_2: 1
Exiting Thread_2

Android - 1. Activity(액티비티)

1. Application

글로벌 어플리케이션 상태를 유지하기 위한 기본 클래스 입니다.
AndroidManifest.xml의 application에서 name을 지정하여 사용 가능해집니다.


Activity class는 언제든지 스택에서 삭제되고 다시 불러오게 되지만 Application class는 한번 불리면 앱이 종료될 때 까지 유지됩니다.


2. Activity

Activity class를 사용하면 UI와  View를 배치 할 수 있는 창을 처리합니다. 모든 Activity들은 반드시 AndroidManifest.xml에 <activity>로 정의 되어야 합니다. Activity는 다른 Activity들의 method를 직접 호출할 수 없으며 데이터도 직접 액세스 할 수 없습니다.


3. Activity Lifecycle

Activity들은 activity stack으로 관리되며 새 Activity가 실행되면 stack의 상단의 배치됩니다.

Activity는 기본적으로 4가지 상태가 있습니다.

  1. Running - Activity가 화면의 foreground에 위치, 시스템 리소스가 부족해도 거이 중단되지 않는다.
  2. Paused - 화면에는 보이지만 다른 Activity가 일부분 가린 상태, 빠른 복귀를 위해 모든 상태정보를 유지하고 윈도우매니저에 연결을 유지하나 매우 낮은 메모리 상태에서 중지될 수 있다.
  3. Stopped - 완전히 다른 Activity에 의해 가려지는 경우, 상태정보와 윈도우매니저에 연결을 유지하나 중단될 가능성이 높다.
  4. Killed - 시스템 리소스가 부족할 때 메모리에서 중단되는 경우 해당 Activity들은 다시 시작되어야 한다.




4. Fragment

honeycomb부터 사용 가능한 Fragment는 Activity를 구현하는데 코드를 좀 더 모듈화 하고, 대형화면에 대해 정교한 사용자 인터페이스를 구축하고, 크고 작은 화면의 Application을 확장하는데 도움을 줍니다.







Python socket programming #2 - MultiThreading (Thread module)

파이썬에서의 멀티 쓰레딩은 두 가지의 모듈을 사용해 만들 수 있습니다.

각각의 모듈은 아래와 같습니다.


  • Thread
  • Threading


먼저 Thread는 C와 같이 함수를 이용해 Thread를 run 시키는 방식으로 MultiThreading을 구현합니다.

Threading은 흔히 자바에서 보던 방식처럼 Thread관련 클래스를 상속받아 run을 override 하여 사용합니다.

이 포스팅에선 먼저 Thread만 다루도록 하겠습니다.

1. Thread


기본적으로 Thread에서 thread를 run시키는 함수는 아래와 같습니다.

thread.start_new_thread( function, (argument))

아래 소스코드를 확인 해 보겠습니다.

위의 print_num함수에 threadName과 delay인자를 준 뒤

delay 시간만큼 텀을 두고 숫자를 1~5까지 출력하는 함수 입니다.

이 함수를 각 각 1초와 2초로 설정하여 두개의 쓰레드를 작동 시키는 프로그램입니다.

출력값은 synchronizing이 되어있지 않아 값이 겹쳐 나올 수 있게 됩니다.

마지막의 while은 Main Thread를 종료시키게 되면 생성된 2개의 쓰레드도 죽게 되므로

이를 막기위해 Main Thread에 무한루프를 걸어줍니다.

아래는 출력값 입니다.

Thread_1: 1
Thread_2: 1Thread_1: 2

Thread_1: 3
Thread_2: 2
Thread_1: 4
Thread_1: 5
Thread_2: 3
Thread_2: 4
Thread_2: 5

Python socket programming #1 - basic server and client

python의 소켓은 C나 자바에 비해 비교적 단순한 모습을 취하고 있습니다.

Socket의 선언은 아래와 같습니다.

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

여기서 각각 PF(프로토콜 체계)와 AF(주소 체계)를 살펴보면

A. PF

  • PF_INET - IPv4 프로토콜
  • PF_INET6 - IPv6 프로토콜
  • PF_LOCAL - Local 통신 UNIX 프로토콜
B. AF
  • AF_INET - IPv4 프로토콜
  • AF_INET6 - IPv6 프로토콜
  • AF_LOCAL - Local 통신 UNIX 프로토콜
이를 통해 소켓을 만들 때에 사용하고자 하는 프로토콜을 사용할땐 PF를 주소 구조체 안에 주소 체계를 정의할 때엔 AF를 사용합니다.

기본적으로 C에서 socket을 생성 할 때 PF_INET을 사용하지만, Python에는 PF가 없습니다.

그리고 뒤에오는 SOCK_STREAM과 SOCK_DGRAM을 통해 각 각 TCP UDP를 결정하게 됩니다.


Socket에 대한 binding은 아래와 같이 선언합니다.

s.bind((host, port))

위와 같이 소켓 선언과 바인딩이 타 언어에 비해 아주 심플한 모습을 취하고 있습니다.

소켓을 통해 간단하게 값을 한 번만 주고 받는 에코서버를 작성해보도록 하겠습니다.

1. Server


서버에서 원격지의 소켓을 받기 위한 listen은 아래와 같이 선언합니다. 이 부분은 C의 서버 프로그래밍과 유사합니다.

s.listen(5)

listen을 통해 소켓이 개통이 되는데 뒤의 인자 backlog는 커널이 관리하는 대기 큐에서
연결 요청을 하고 기다리는 총 클라이언트의 수 입니다.

위 큐에 연결 요청한 소켓은 SYN_RCVD나 ESTABLISHED 상태로 대기합니다. 이 함수를 호

출하면 커널은 내부적으로 소켓의 상태를 CLOSED에서 LISTEN으로 바꿔줍니다.

Status

  • SYN_RCVD - 클라이언트가 connect 함수로 서버에 요청한 연결을 처리하기 위해 SYN 패킷을 통한 3-Way Handshaking을 진행하는 중입니다.
  • ESTABLISHED - 3-Way Handshaking이 모두 완료되면 이 상태가 됩니다.

마지막으로 클라이언트의 연결을 위한 accept 함수는 아래와 같습니다.

c = s.accept()

위를통해 클라이언트 소켓을 Accept 할 수 있습니다.

이제 send와 recv를 통해 값을 주고 받을 수 있습니다.

socket.send("connect success")

socket.recv(1024)

서버 소스는 아래와 같습니다.


먼저 socket.socket()를 통해 소켓을 생성 한 뒤

9999번 포트의 루프백 ip 127.0.0.1로 bind 해줍니다.

s.listen(5)와 s.accept()를 통해 클라이언트 소켓을 연결 한 뒤

send를 통해 'Connection success'를 전송 해 줍니다.

클라이언트가 들어오기 전 c, addr = s.accept()에서 대기중인 실행 모습은 아래와 같습니다.

listen ok


2. Client


Client 또한 마찬가지로 socket.socket()를 통해 소켓을 생성 해 줍니다.

그리고 아래와 같이 connect() 함수를 통해 해당 ip 127.0.0.1과 9999번 포트에 소켓을 연결 해 줍니다.

s.connect((host, port))

그리고 recv를 통해 상대방의 send를 기다립니다.

s.recv(1024)

서버와 클라이언트의 실행 결과는 아래와 같습니다.

-----------------------Server-----------------------
listen ok
connection ('127.0.0.1', 2617)
-----------------------Client------------------------
Connection success
-----------------------------------------------------

python - Reading Excel sheet with xlrd (xlrd를 이용한 파이썬 엑셀 파일 읽기)

1. xlrd

시작에 앞서 python xlrd패키지를 설치해야 합니다.
https://pypi.python.org/pypi/xlrd/0.7.9

xlrd와 xlwd 두개의 패키지가 존재하는데, xlrd는 read용 패키지 xlwd는 write용 패키지 입니다.

먼저 포스팅에 사용할 엑셀 Sheet은 아래와 같이 작성됐습니다.

Sheet1

Sheet2









2. Open the Excel files and sheets


위와 같이 xlrd를 import 해줍니다.

Lien 4 - xlrd.open_workbook()을 통해 Excel파일을 읽어옵니다.

Line 5, 13  - sheet_by_index()를 통해 line 5에선 Sheet1 line 13에선 Sheet2를 각각 열람 할 수 있습니다.

Line 6 - ncols를 통해 열람한 Sheet의 컬럼의 갯수를 확인 할 수 있습니다.

Line 7 - nrows를 통해 열람한 Sheet의 로우의 갯수를 확인 할 수 있습니다.

출력결과 아래와 같습니다.

-------- Sheet1 --------
Number of col: 4
Number of low: 4
-------- Sheet2 --------
Number of col: 2
Number of low: 2

3. Get values in excel file


row_values와 col_values를 통해 각 각 row와 col의 값을 구할 수 있습니다.

row_values(0)을 이용하면 엑셀의 1번 줄 [1A, 1B, 1C, 1D]를 출력 할 수 있습니다.

col_values(0)을 이용하면 엑셀의 A컬럼 [1A, 2A, 3A, 4A]를 출력 할 수 있습니다.

출력결과 아래와 같습니다.

-------- Sheet1 --------
Number of col: 4
Number of low: 4
-------- Values of low --------
[u'1A', u'1B', u'1C', u'1D']
[u'2A', u'2B', u'2C', u'2D']
[u'3A', u'3B', u'3C', u'3D']
[u'4A', u'4B', u'4C', u'4D']
-------- Values of col --------
[u'1A', u'2A', u'3A', u'4A']
[u'1B', u'2B', u'3B', u'4B']
[u'1C', u'2C', u'3C', u'4C']
[u'1D', u'2D', u'3D', u'4D']


4. values are saved the list


row_values(0)이 [1A, 1B, 1C, 1D]의 정보를 가지고 있습니다.

결론적으로 1A만 불러오려면 row_values(0)[0]을 이용하면 1A만 출력 할 수 있습니다.

이를 통해 Python의 list에 엑셀파일의 모든 컬럼이 가지고있는 값을 저장 할 수 있습니다.

출력결과 아래와 같습니다.

-------- Sheet1 --------
Number of col: 4
Number of low: 4
-------- Values of Excel file --------
['1A', '1B', '1C', '1D']
['2A', '2B', '2C', '2D']
['3A', '3B', '3C', '3D']
['4A', '4B', '4C', '4D']

DHCP ServerSetting

Objectives
-ubuntuRed-Hat계열 Linux에서의 DHCP Server Setting
 
InstallSetting 전 확인 사항
1. Linux계열 확인
2. Root계정 권한 획득
 
 Install

























<Ubuntu>
# apt-get install isc-dhcp-server

<Red-Hat/CentOS>
# Yum install dhcp


위와 같은 방법으로 dhcp패키지를 설치 해 줍니다.

Configure

# vi /etc/dhcp/dhcp.conf
위 커맨드를 실행 한 뒤 dhcp serverconfigure해줍니다.





16/17line에서 domain-name을 설정 해 줄 수 있습니다.


























52 ~ 60line을 통해 dhcp serverconfigure합니다.
1.     53 – 사용하고 있는 ipsubnet정보를 입력 해 줍니다.
2.     54 – dhcp client가 받게 될 ip의 범위를 입력 해 줍니다.
3.     55,56 – 위에서 바꾼 domain name을 입력 해 줍니다.
4.     57 – gateway ip를 입력 해 줍니다.
5.     58 – broadcast-address ip를 입력 해 줍니다.
6.     59,60 – lease timeip의 대여 시간 이며 *lease timelinuxtime-zone의 영향을 받지 않습니다.


Service start
<Ubuntu>
# /etc/init.d/isc-dhcp-server start
* Stopping ISC DHCP server dhcpd    [ OK ]
* Starting ISC DHCP server dhcpd    [ OK ]

# unset UPSTART_SESSION
# service isc-dhcp-server restart
Isc-dhcp-server stop/waiting
Isc-dhcp-server start/running, process 8570

<Red-Hat/CentOS>
# service dhcpd restart
Isc-dhcp-server stop/waiting
Isc-dhcp-server start/running, process 8570



Maintenance

# cat /var/lib/dhcp/dhcp.leases

위 커맨드를 통해 clientserver에서 ip를 받아간 정보를 확인 할 수 있습니다.

























# tail f /var/lib/dhcp/dhcp.seases

위 커맨드를 통해 실시간으로 clinetip를 받아가는 정보를 확인 할 수 있습니다.





















<Ubuntu>
# vi /var/log/syslog

<Red-Hat/CentOS>
# vi /var/log/message


위 커맨드를 통해 시스템 로그에서 dhcp 서버가 client에게 ip를 할당하는 모습이나 error등을 체크 할 수 있습니다.