토익스피킹 공부한다고 한창 할 때... 생각나서 만들어본 타이머...

토익스피킹 처럼 준비시간/답변시간을 입력하면 카운트를 보여준다

beep음을 추가하면 더 좋았을 것 같지만 이미 더 좋은 타이머들이 많고

카운트 되는 숫자가 타이머와 일치하지 않은 버그도 있어서 

한 번 타이머를 써본 것에 의의를 둔 기억이..

 

먼저 main함수를 보면 준비시간과 답변시간을 입력 받아 순차적으로 timer를 동작시킨다. 

이때 timer를 카운트 하기 위해 TimerTick이란 함수를 사용하였다.

func main() {
	pTime := os.Args[1]
	sTime := os.Args[2]
	pt, _ := strconv.Atoi(pTime)
	st, _ := strconv.Atoi(sTime)
	pTimer = time.NewTimer(time.Second * time.Duration(pt))
	pState := 0
	log.Println("Prepare Time Start")
	go TimerTick(pt)
	for {
		select {
		case <-pTimer.C:
			log.Println("PreTime END")
			pState = 1

		}
		if pState == 1 {
			break
		}
	}
	aTimer = time.NewTimer(time.Second * time.Duration(st))
	aState := 0
	log.Println("Answer Time Start")
	go TimerTick(st)
	for {
		select {
		case <-aTimer.C:
			log.Println("AnswerTime END")
			aState = 1
		}
		if aState == 1 {
			break
		}
	}
}

 

1초마다 Cnt수를 콘솔에 출력하기 위해 만들었다. 

(지금보니 리턴은 왜 한지 모르겠지만...)

고루틴으로 실행하였기에 실제 준비시간 또는 답변시간의 타이머의 시작 시간과 차이가 있어 정확히 시간이 카운트 되지 않는 버그가 있지만.....

실제 시험에서는 긴장을 하고, 어떤 변수가 있을 지 모르기에

카운트가 조금 짧게 느껴지도록 연습하면 되지 않을까 위안을 삼았던 기억이 있다...ㅎ

func TimerTick(cnt int) bool {
	ticker := time.NewTicker(time.Second)
	for {
		select {
		case <-ticker.C:
			if cnt == 0 {
				break
			}
			log.Println("CNT : ", cnt)
			cnt--

		}
	}
	return true
}

아무튼 timerTick함수로 카운트를 출력하는 것을 제외하고는 정해진 시간만큼 대기하는 기능은 잘 동작하는 것 같았다

 

실행 결과

 

끝!

반응형

엄청나게 오랜만에 우연히 생각나서 올리는 게시글...

 

Ping 테스트를 반복적으로 하는 프로그램 

가끔 전원 On/Off 테스트에 사용하거나 네트워크 체크할 때 사용했던 기억이 가물가물.... 

 

Ping테스트를 할 타겟 IP와 반복적으로 할 간격[초]을 인자로 받아서 실행하도록 하였다.

func main() {
	target := os.Args[1]
	t := os.Args[2]
	timeDelay, err := strconv.Atoi(t)
	if err != nil {
		log.Println("ERR : ", err)
	}
	log.Println("Start")
	for {
		if !pingCheck(target) {
			log.Println("Stop")
			break
		}
		time.Sleep(time.Second * time.Duration(timeDelay))
	}
}

 

Ping 테스트는 3번 시도하여 100%성공이 아니면 실패로 리턴하도록 하였다. 

func pingCheck(target string) bool {
	out, err := exec.Command("ping", target, "-c 3").Output()
	if err != nil {
		log.Println("ERR : ", err)
	}
	log.Println(string(out))
	if strings.Contains(string(out), "Destination Host Unreachable") || strings.Contains(string(out), "errors") {
		log.Println("Down")
		return false
	}
	if strings.Contains(string(out), "0% packet loss") {
		n := strings.Index(string(out), "0% packet loss")
		if string(out[n-1]) == "0" && string(out[n-2]) == "1" {
			log.Println("Down")
			return false
		}
	} else {
		log.Println("Down")
		return false
	}

	log.Println("Alive")
	return true
}

 

3번 중 2번만 성공해도 성공으로 할 경우, 패킷 성공률 비교하는 부분을 기호에 맞게 수정하면 된다.

 

실행 결과

끝!

반응형

언제 만들었는지는 잘 기억도 안나지만.....폴더 구석에서 찾은 Go를 이용한 크기가 동일한 2개 파일이 같은지 비교하는 프로그램

(평문을 암호화했다가 다시 복호화해서 원본과 같은지 잠깐 확인해보려고 했던가...?)

 

main은 간단히 보면 파일 2개를 읽어서 비교, 일치하면 OkCnt 증가 

var bufSize = 512

func main() {
	file1 := os.Args[1]
	file2 := os.Args[2]

	f1, idx1 := readFile(file1)
	f2, _ := readFile(file2)
	okCnt := 0
	match := 0
	for i := 0; i < idx1+1; i++ {
		match = 0
		for j := 0; j < len(f1[idx1]); j++ {
			if f1[idx1][j] != f2[idx1][j] {
				fmt.Println("not match")
				match = 1
			}
		}
		if match == 0 {
			okCnt++
		}
	}
	fmt.Println("okcnt : ", okCnt)
}

 

 

파일을 읽을 때 사용한 함수 

파일 전체 크기를 버퍼 크기 512바이트를 기준으로 나누고 [][]byte를 만들어 파일을 모두 읽음

해당 읽은 파일의 버퍼와 Index수를 반환하는 함수

func readFile(inputFile string) ([][]byte, int) {
	file, err := os.Open(inputFile)
	if err != nil {
		fmt.Println(err)
	}
	defer file.Close()

	testBufSize := bufSize
	fileStat, err := file.Stat()
	if err != nil {
		fmt.Println(err)
		return nil, -1
	}
	fb := bufio.NewReader(file)
	var fileData [][]byte
	fileSize := fileStat.Size()
	idx := int(fileSize) / testBufSize
	remain := int(fileSize) % testBufSize
	fmt.Println("filesize : ", fileSize, "idx :", idx, "remain", remain)
	if remain != 0 {
		idx = idx + 1
	}
	fileData = make([][]byte, idx)

	dataIdx := 0
	// filelen := 0

	for i := 0; i < idx; i++ {
		if remain != 0 {
			if i == idx-1 {
				fileData[i] = make([]byte, remain)
				// filelen += len(decryptDataBuf[i])
				io.ReadFull(fb, fileData[dataIdx])
				// fmt.Println("F Len ", filelen, "dlen :", len(fileData[dataIdx]))
				break
			}
		}
		fileData[i] = make([]byte, testBufSize)
		// filelen += len(decryptDataBuf[i])

		io.ReadFull(fb, fileData[dataIdx])
		// fmt.Println("F Len ", filelen, "dlen :", len(fileData[dataIdx]))
		dataIdx++
	}

	return fileData, dataIdx

}

 

실제 동일한 파일을 이름만 바꾸어 테스트한 결과와 크기가 다른 파일을 테스트한 결과 

크기가 다른 파일이면 버퍼의 index가 일치하지 않아서 바로 오류가 나버리는 급조한 프로그램... 

 

반응형

Linux에서 Golang 으로 GPIO를 제어해보았다. 

 

GPIO란? GPIO(General Purpose Input Output)는 일반적인 용도의 입출력 포트를 의미한다. 

 

NewGPIO로 구조체를 만들고, Pin(string)으로 제어할 GPIO 핀번호를 정한다. 

Out , In 으로 dir을 정하고 , High, Low로 값을 정하고, PinRead 로 해당 GPIO 값이 0인지 1인지 읽을 수 있다. 

PinUnexport로 사용을 종료할 수도 있다. 

 

핀을 초기화하고, 방향과 Low,High를 정해 사용할 수 있다. 

예를 들면

g:=NewGPIO()

g.Pin("1")

g.Out().High()

g.In().Low() 등등 

 

전체코드는 다음과 같다.

// gpio.go
package gpio

import (
	"io/ioutil"
	"log"
	"os"
)

const (
	gpioBasePath     = "/sys/class/gpio"
	gpioExportPath   = "/sys/class/gpio/export"
	gpioUnexportPath = "/sys/class/gpio/unexport"
)

type GPIO struct {
	pin string
}

func NewGPIO() GPIO {
	return GPIO{}
}

func (g GPIO) Pin(pin string) GPIO {
	g.pin = pin
	if _, err := os.Stat(gpioBasePath + "/gpio" + g.pin); os.IsNotExist(err) {
		err := ioutil.WriteFile(gpioExportPath, []byte(g.pin), 0666)
		if err != nil {
			log.Println(err)
		}
	}
	return g
}

func (g GPIO) Out() GPIO {
	err := ioutil.WriteFile(gpioBasePath+"/gpio"+g.pin+"/direction", []byte("out"), 0666)
	if err != nil {
		log.Println(err)
	}
	return g
}

func (g GPIO) In() GPIO {
	err := ioutil.WriteFile(gpioBasePath+"/gpio"+g.pin+"/direction", []byte("in"), 0666)
	if err != nil {
		log.Println(err)
	}
	return g
}

func (g GPIO) High() bool {
	err := ioutil.WriteFile(gpioBasePath+"/gpio"+g.pin+"/value", []byte("1"), 0666)
	if err != nil {
		log.Println(err)
		return false
	}
	return true
}

func (g GPIO) Low() bool {
	err := ioutil.WriteFile(gpioBasePath+"/gpio"+g.pin+"/value", []byte("0"), 0666)
	if err != nil {
		log.Println(err)
		return false
	}
	return true
}

func (g GPIO) PinRead(pin string) byte {
	value, err := ioutil.ReadFile(gpioBasePath + "/gpio" + pin + "/value")
	if err != nil {
		log.Println(err)
	}

	return value[0] - 48
}

func (g GPIO) PinUnexport(pin string) bool {
	err := ioutil.WriteFile(gpioUnexportPath, []byte(pin), 0666)
	if err != nil {
		log.Println(err)
		return false
	}
	return true
}

끝 !

반응형

이번엔 Golang에서 제공되는 라이브러리를 이용하여 AES CFB 암호화를 하고 Base64로 인코딩 하였다.

암호화 이론은.... 설명할 수준까지는 안되기에 다른 자료나 블로그들을 참조하였다

CFB로 암호화하고 Binary 데이터를 String 형태로 변경하는 Base64까지 적용하였다.

실행할 때 Key값을 인자로 넣고 실행을 한다.

그 후, 암호화할 내용들을 입력하면 끝 !

Base64를 적용하지 않으려면 EncryptAESCFB까지만 진행하면 된다.

윈도우용으로 사용하려면 크로스 컴파일 하면 무난히 사용 가능할 듯 하다.

- 소스코드

// main.go
package main

import (
	"bufio"
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"encoding/base64"
	"fmt"
	"os"
)

var iv = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}

func main() {
	keyValue := os.Args[1]
	key := make([]byte, 16)
	md5Key := md5.Sum([]byte(keyValue))

	for i, v := range md5Key {
		key[i] = v
	}

	scanner := bufio.NewScanner(os.Stdin)

	for scanner.Scan() {
		ucl := scanner.Text()
		fmt.Println("----------------------------------")
		fmt.Println("Plain Data : ")
		fmt.Printf("[")
		for i, val := range ucl {
			if i == len(ucl)-1 {
				fmt.Printf("0x%02X", val)
			} else {

				fmt.Printf("0x%02X, ", val)
			}
		}
		fmt.Printf("]\n")
		fmt.Println(ucl)

		encrypted := make([]byte, len(ucl))
		err := EncryptAESCFB(encrypted, []byte(ucl), key, iv)
		if err != nil {
			panic(err)
		}
		fmt.Println("\nEncrypted Data : ")
		fmt.Printf("[")
		for i, val := range encrypted {
			if i == len(encrypted)-1 {
				fmt.Printf("0x%02X", val)
			} else {

				fmt.Printf("0x%02X, ", val)
			}
		}
		fmt.Printf("]\n")

		// fmt.Printf("[ 0x% X, ]\n", encrypted)
		fmt.Println(string(encrypted))

		sEnc := base64.StdEncoding.EncodeToString(encrypted)
		fmt.Println("\nbase64 Data :")

		fmt.Printf("[")
		for i, val := range sEnc {
			if i == len(sEnc)-1 {
				fmt.Printf("0x%02X", val)
			} else {

				fmt.Printf("0x%02X, ", val)
			}
		}
		fmt.Printf("]\n")
		fmt.Println(sEnc)

	}

}

func EncryptAESCFB(dst, src, key, iv []byte) error {
	aesBlockEncrypter, err := aes.NewCipher([]byte(key))
	if err != nil {
		return err
	}
	aesEncrypter := cipher.NewCFBEncrypter(aesBlockEncrypter, iv)
	aesEncrypter.XORKeyStream(dst, src)
	return nil
}

func DecryptAESCFB(dst, src, key, iv []byte) error {
	aesBlockDecrypter, err := aes.NewCipher([]byte(key))
	if err != nil {
		return nil
	}
	aesDecrypter := cipher.NewCFBDecrypter(aesBlockDecrypter, iv)
	aesDecrypter.XORKeyStream(dst, src)
	return nil
}

실행 화면

테스트는 실행할 때, ABCD라는 키값을 넣고 1234ABC 라는 평문을 넣었다.

CFB 암호화와 추가로 Base64 인코딩을 했을때 까지 단계별로 확인할 수 있다.

출력은 Hex와 String으로 모두 확인 가능하다.

혹여나 다른 프로그램 코드에서 IP 나 Port 등과 같은 정보들을 암호화 해서 하드코딩 했는데

다음에 변경하여야 할 경우 혹은 테스트용으로 잠시 변경해야할 경우...

나름 유용하게 쓸 수 있지 않을까...? 는.... 내가 몇번 잘 썻다...ㅎ

끝!

 

반응형

[]byte를 INT보다  HEX 데이터로 출력할 때가 생각보다 많은 것 같다. 

 

 

 위와 같은 iv []byte를 fmt.Println하면 아래와 같이 int형으로 출력이 된다. 

이를 hex형태로 보고 싶다면 예전에는 for문을 이용해서 아래와 같이 출력했다.....(미련하게...)

 

 

하지만 형식지정자를 사용하면 쉽게 출력 할 수 있었다.

좀 더 보기 좋게 하기 위해서 %뒤에 한칸 띄워서 각 바이트들이 띄워쓰기가 되도록 하고 \n을 넣어 마지막에 줄바꿈도 추가하였더니 

 

깔끔하게 출력되었다. 

 

엄청 기본적이고 쉬운 내용이였지만 그냥 지나쳐버려 비효율적인 방법을 반복하고 있었다......

반응형

Golang에서 제공되는 라이브러리를 이용하여 AES CBC 암호화를 하였다.

 

암호화의 기본 이론들이나 원리들은 잘 모르지만....

 

처음에 block size보다 작은 크기는 0을 추가하여 zero padding을 하고 암호화를 하였는데,

 

다시 복호화를 하였을 때 0이 남아있었다. (원래 그런건지.. 내가 잘못한건지...)

 

그래서 pkcs7Pad를 이용하였다.

 

패딩할때는 block size크기에 부족한 만큼 0 대신 그 크기를 넣었고, 

 

다시 읽을 때는 맨 마지막 바이트를 읽어 그 크기 만큼 빼고 읽었다. 

 

출력 결과

 

pkcs7Pad 패딩을 할 때는 빈 byte slice를 만들어 copy할 수도 있지만,  버퍼를 만들어 추가하는 형식으로 했다. 

pkcs7Unpad 언패딩은 암호문의 맨마지막 수를 읽고, 해당 수 만큼을 제외하고 나머지를 읽도록 하였다.

 

CBC 암호화전에 pkcs7Pad 해주고, 복호화하고 pkcs7Unpad 해주면 된다.

 

반응형

파일을 Hex array로 변환하고 C 헤더파일로 만드는 간단한 프로그램..

만들었지만 사용은 하지않고 있는 중.. 어딘가 사용되겠지..?

 

전체적인 구조는 다음과 같다. 

 

1. 변환하려는 파일을 Open한다. 

2. Output 파일에 먼저 헤더파일 형식(#include .. 등등 )을 Write 한다. 

3. 변환하려는 파일을 한 바이트씩 읽어 HEX형태로 Write한다. 

4. 끝!

 

전체적인 코드

 

반응형

+ Recent posts