레이블이 Network인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Network인 게시물을 표시합니다. 모든 게시물 표시

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

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
-----------------------------------------------------

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등을 체크 할 수 있습니다.

multithreading network programming - 3. multi client echo server(멀티스레드 네트워크 프로그래밍 - 다중접속 에코서버)



13라인의 idx를 이용해 클라이언트의 번호를 저장합니다. 14라인의 socklist[100]에 클라이언트 정보를 저장합니다.(총 100명) 26번 라인에서 socklist를 전부 -1로 초기화해줍니다. 51,52라인을 통해 클라이언트 소켓을 socklist에 클라이언트 소켓정보를 저장하고 idx의 값을 증가시켜줍니다. 76라인을 통해 클라이언트 소켓이 저장되지 않은 -1이 나올때까지 반복문을 돌리면서 저장된 모든 클라이언트에게 메세지를 전송합니다.

multithreading network programming - 2. echo server(멀티스레드 네트워크 프로그래밍 - 에코서버)

간단한 에코서버입니다.














41번 라인에서 accept 한 후 리턴받은 connSock의 값을

43번 라인에서 쓰레드를 생성하면서 값으로 넘겨줍니다.

그럼 47번 라인에 생성된 쓰레드 내부의 54번라인 반복문 안에서

클라이언트와 지속적으로 통신을 받아서 받은 내용을 돌려주게됩니다.

multithreading network programming - 1. multithread(멀티스레드 네트워크 프로그래밍)






 멀티스레드는 프로세스 내부에서 두가지의 작업을 동시에 실행하는것을 의미합니다. fork의 경우 자기 자신과 똑같은 완전 새로운 프로세스를 복제하지만 thread의 경우 원하는 작업을 테스크 형태로 생성합니다.




 간단한 Thread 예제


#include <stdio.h>
#include <pthread.h>
#define NUM_THREADS 3

void *thread_ (void *arg)
{
       printf("get_id[%d] = %lu \n", arg, pthread_self());
       return arg;
}

main()
{
       pthread_t tid[NUM_THREADS];
       int i, status;

       for(i=0; i < NUM_THREADS; i++) {
              status = pthread_create (&tid[i], NULL, thread_, (void *) i );
       }

       pthread_exit(NULL);
}



이 예제는 쓰레드를 세개 생성하여 쓰레드 고유 id를 출력하는 예제입니다.

위의 pthread_create 함수를 이용해 쓰레드를 생성합니다.

내부 인자로는

1. &tid[i] -> 스레드가 생성될때 스레드의 ID가 저장될 위치의 주소를 가르킵니다.

2. NULL -> 생성할 스레드의 속성을 설정할때 사용하는데 대부분 NULL을 사용합니다.

3. thread_ -> 쓰레드가 실행시킬 (void *)형의 함수를 가르킵니다. 위 코드에선 선언된 *thread_ 함수를 불러옵니다.

4. (void *) i -> 쓰레드에 의해 호출되는 함수에 전달하는 인자입니다. thread_함수에선 *arg로 받게됩니다.

pthread_create 함수의 수행이 성공적으로 끝나면 0을 실패하면 오류코드를 반환합니다.

위 예제에서는 define된 NUM_THREADS만큼 for문 내에서 스레드를 생성합니다.

생성된 스레드는 각각 0과 1,2를 thread_함수로 넘겨주고 함수내에서는 전달받은 인자와 pthread_self()를 이용해 쓰레드의 고유 id를 출력해줍니다.

출력결과입니다.