PC 프로그램 내부의 화면 표시 스케일을 수정해 달라는 요청이 왔다.

기존엔 1152.00으로 표시되는 걸 11.52로 표시해달라는 것...

 

원시 데이터를 가공하는 부분을 다음과 같이 수정했다.

 

double volB = Convert.ToInt32(hexStrVolB, 16) / 100;

 

이랬더니 문제가...

 

소숫점 자리수는 앞으로 두자리 땡겨지는데 마지막 두 자리를 버림 처리 해버리는 것이였다.

 

찾아보니 

 

https://bumday.tistory.com/193

 

[C#] int형 변수끼리 나눗셈 결과 소숫점 이하 값이 버려지는 현상

JavaScript과 같은 동적 타이핑(dynamic typing)을 지원하는 언어를 사용하다가 C#으로 넘어와 개발하다보면 자료형에 대해 간과하다가 이슈가 생길 때가 있다 . 이번 포스팅에서는 int형 변수끼리 나눗

bumday.tistory.com

 

아...

C#에서의 나눗셈은 정수 나누기 정수를 하면

결과가 실수더라도 실수가 저장되지 않고 소숫점 이하값이 버려지고 

정수부만 변수에 들어간다는 것...

 

double volB = (double)Convert.ToInt32(hexStrVolB, 16) / 100; 나

 

double volB = Convert.ToInt32(hexStrVolB, 16) / 100.0;

 

처럼 한 쪽이 실수형이여야한다는 것.

 

지식이 늘었다.

'Tech > C#' 카테고리의 다른 글

C# Modbus 프로그램 간혈적 통신 중단 해결기  (0) 2024.07.02

 

얼마 전 싼맛에 XMP 풀뱅크를 한답시고 듀얼킷 두개를 야심차게 산 적이 있었다.

 

팀그룹 티포스 CL18 3600 메모리로 기억하는데, 

 

두개 두개 나눠 끼면 XMP 수치가 잘 들어가고

 

풀뱅을 했다간 거의 모든 램타이밍과 클럭에서 부팅 실패 / 게임 크래시 / PC 멈춤 등 불안한 모습이 보였다.

 

QVL 리스트에도 있었는데 왜 이러지 미친듯이 찾아본 결과 그냥 태생이 그런 거란다.

 

깡수율이 좋은 램이면 풀뱅해도 XMP를 먹거나 전압 조정 램타 조정 통해서 먹는 경우도 있지만

 

포텐셜이 낮은 메모리의 경우 쉽지 않다고...

 

바로 수업료 지불하고 반품 했다.

 

사용자와 장비 사이에 껴서 원격으로 장비의 데이터를 확인할 수 있게 해주는 HMI라는 녀석은

장비가 없으면 깡통에 불과하다.

 

그 깡통인 HMI를 유지보수하는 게 주 업무 중 하나인데, 

불특정 시간마다 되면 PC 프로그램과 장비의 연결이 끊긴다는 내용을 전달 받았다.

 

 

일반적인 인터넷 환경과 달리

이런 전기 산업 쪽 장비는 HMI가 클라이언트가 되어 서버 역활을 하는 장비에게 데이터를 요청하고, 

요청을 받은 장비는 내부 메모리 데이터를 긁어다가 패킷을 보내준다.

HMI 프로그램은 받은 데이터를 해석하고, 맵핑하여 사용자에게 전시하는 역활을 하고,

사용자 조작을 반대로 장비로 전송하기도 한다.

 

하지만 그 과정에서 누군가가 연결을 끊어버려 그 절차가 진행되지 않는 것.

 

처음에는 일반적인 인터넷 환경을 상정하고 PC SW가 서버, 장비가 클라이언트라 생각했으나

PC 측의 연결 함수를 아무리 뜯어봐도 서버 역활을 하는 것 같지는 않았다.

소캣 연결 절차를 따라가봐도 내가 상대방에게 요청하는 것 밖에 없네?

 

...내 생각이 잘못된걸 그때서야 알았다. 아 이거 완전 반대구나.

 

내 환경에서는 죽어도 재현이 안됐기에 고민 끝에 다음과 같은 방식으로 증상을 재현하였다.

 

1. 우선 PC와 연결할 때는 장비 전원을 켜둔다. (소켓 열림)

 

2. 데이터를 한번 요청하여 화면에 제대로 표시되는 지 확인한다.

 

3. 장비 전원을 껐다가 다시 켠 후 데이터를 요청하여 전달받은 문제가 발생한지 확인한다.(소켓 닫힘)

 

 

실제 원인은 이랬다.

 

모종의 이유로 장비 측에서 PC 프로그램과의 소켓을 끊어버린 것.

 

PC 프로그램은 별도의 소켓 Life Check를 진행하지 않고 있기 때문에 

데이터 값이 문제 있다는 오류 메세지만 출력되고 있었다.

 

그 상황에서 연결 설정을 통해 다시 연결하고 데이터를 요청하면 정상적으로 받아왔다.

 

그렇다고 나는 FW 개발자가 아니니 장비 소스코드를 뜯어볼 수도 없는 노릇.

 

그래서 PC 프로그램의 연결 소스코드를 수정하여 해결하기로 했다.

 

C#의 Socket 클래스를 살펴본 봐 Poll과 Available 이라는 기능이 있는 걸 알 수 있었다.

Poll은 인자로 최대 시간(MS)와 Mode를 받아 결과를 반환한다.

  • SelectMode.SelectRead: 소켓이 읽기 가능한 상태인지 확인.
  • SelectMode.SelectWrite: 소켓이 쓰기 가능한 상태인지 확인.
  • SelectMode.SelectError: 소켓에 오류가 있는지 확인.

Available 은 소켓에 수신 대기중인 바이트가 얼마나 있는지 감지하는 기능이다.

 

해당 함수를 활용하면 소켓 연결을 확인할 수 있을 것으로 생각 되어 코드를 아래와 같이 작성하고 적용하였다.

C#-소켓통신간-클라이언트-끊어짐-감지

 

우선 통신 연결이 처음 성공하면 모니터링 함수를 통해 1초 간격으로 소켓 상태를 확인하고

수신 대기중인 바이트를 계산하여 0바이트인지 확인한다.

 

 

Poll과 Available의 결과가 true로 반환되어 소켓 닫힘이 감지되면 아래의 재 연결 함수로 이동하게 된다.

 

 

해당 함수는 소켓 연결을 재 시도하고, 오류가 발생하면 5초 뒤에 다시 시도하는 역활을 하게 된다.

 

 

해당 작업된 결과물 송부해서 지금까지도 기다려본 바,

 

다행이 별 다른 피드백은 없는 것으로 보아하니...

고안했던 방법이 잘 먹힌 거 같다.

 

2주~3주 넘게 고민했는데 쉽게 풀려서 정말 다행였다랄까.

 

 

'Tech > C#' 카테고리의 다른 글

C#의 정수형 나눗셈시 주의사항.  (1) 2025.02.21

최종프로젝트에서 뭘 했는지 시간이 지나 까먹기 전에, 기록 차원에서 글을 남겨 본다.

 

0. 기술 스택 변경 

도저히 진도가 나가지 않는 Node Js 기반의 서버 활용을 그만두고, JSP/Servlet 기반으로 돌아가기로 했다.

간단한 기능 구현 조차도 자꾸 막히고, 시간은 촉박하게 다가오는지라 만장일치로 변경하게 되었다.

일단 전반적인 숙련도가 너무 부족해서 기능 구현을 위해선 끊임없이 배워야 하는데, 하나 해결하면 막히고 하나 해결하면 막히고...정말 미칠 뻔 했다.

 

1. 개발환경 재 셋팅

앞서 사용했던 라즈베리파이를 DB Server로 사용하고 있기에 그에 맞춰 JDBC 드라이버를 변경해서 사용했다.

드라이버로는 mariadb-java-client-2.7.4 사용, 프로젝트 내 WEB-INF/lib 폴더에 복사하여 사용.

 

연결코드는 다음과 같이 변하게 되었다.

ERD 다이어그램, device_seq로 기본 키가 잡혀있는데...이걸 신경 못 쓰고 넘어가 막판에 후회 진짜 많이 했다.

 

2. 센서별 테스트 

초기에는 ESP32 개발보드를 사용하기로 했었다.

다만 주력으로 사용하는 MQ 계열 센서, ZE08-CH2O 센서와의 라이브러리 호환성이 맞지 않고, 

Node MCU ESP-32S 보드의 경우, 보드 리버전에 따라 버그가 있는 경우가 있는데 하필 또 해당되는 보드라

업로드 할 때마다 버튼을 눌러 업로드 모드로 전환시켜줘야 코드가 들어간다고 한다.

 

그래서 결국 돌고 돌아 메가로 도착...

도착한 센서들을 같이 구매했던 도서, 구글 검색결과로 나오는 자료들과 함께 개별 테스트를 먼저 진행했다.

 

포름알데히드 센서의 경우 ZE08-CH2O라는 센서를 사용했는데

연결 방법엔 세가지가 있다..DAC, UART, DFRobot등등..

DAC 방식이 간단해서 그 방법으로 했는데, 멀쩡한 환경인데 자꾸만 Bad가 나와 UART 방식으로 선회,

또다른 문제 봉착으로 인해(코드 통합 시 측정이 진행되지 않음) 결국 DFRobot 방식 썼음.

 

3. MQTT 통신 접목

 

자꾸만 멘토분이 이야기하는 방향과 기술이 멀어저가던 중, 팀장 형이 MQTT에 대해 공부해보더니 이걸 써보자고 했다.

그래서 ESP 8266에서 돌아가게 할려고...꼬박 하루를 고생하던 중 펌웨어 업데이트를 다음과 같이 진행했더니 써먹을 수 있게 되었다.

 

https://mie96.tistory.com/entry/%EA%B4%91%EC%A3%BC%EB%B9%85%EB%8D%B0%EC%9D%B4%ED%84%B0%ED%95%99%EC%9B%90-ESP-8266-%EB%AA%A8%EB%93%88%EC%9D%84-%EC%89%BD%EA%B2%8C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-%EC%9C%84%ED%95%9C-%EA%B0%80%EC%9D%B4%EB%93%9C

 

(광주빅데이터학원) ESP-8266 모듈을 쉽게 사용하기 위한 가이드

2차 프로젝트에서 기존 1차에서 쓰던 방식 (AT 커맨드를 통해 ESP-8266 모듈을 직접 제어하고, GET 방식으로 센서 값 전송) 을 그대로 쓸려다 MQTT 통신을 써 볼려니 문제가 생겼다. ESP8266과 ESP 01 어댑

mie96.tistory.com

PubSubClient 라이브러리에서도 통신기능을 위해 와이파이 라이브러리를 가져다 쓰니 작업이 필수였다. 

 

MQTT 통신의 경우 다음과 같은 도식도를 따른다.

 

우리 시스템의 경우

아두이노에서 각종 환경센서에 대한 정보를 Sensor/total라는 topic으로 publish 하면, 

중간에 라즈베리파이가 이를 중계해주고, 웹 서버에서 topic를 구독해서 값을 받아오게끔 했다.

타 팀이 하고 있던 통합 모니터링 시스템에서는 이러한 topic를 구독만 해 오면 값을 받아올 수 있게 되는 것이다.

 

반대로 각 센서별로 제어하기 위해 마일스 함수를 사용하고, 센서별로 토픽을 각각 만들어 publish 했고, 반대로 웹에선 이러한 내용을 구독한 후, 토픽을 실어 (측정 주기) 보내면 적용되게끔 했다.

 

4. Broker Server 구축 및 통신 테스트 

 

다음과 같은 명령어를 차례대로 입력해 설치를 했다. 

$ wget http://repo.mosquitto.org/debian/mosquitto-repo.gpg.key
$ sudo apt-key add mosquitto-repo.gpg.key 
$ cd /etc/apt/sources.list.d/
$ sudo wget http://repo.mosquitto.org/debian/mosquitto-bullseye.list
$ sudo apt-get update
$ sudo apt-get install mosquitto mosquitto-clients

+로컬 네트워크 환경이면 별다른 설정 필요 없으나 외부에서 접속 시 설정파일 수정이 필수다!

 

mosquitto_sub -t sensor/#

#의 경우 해당 토픽 아래의 모든 내용을 가져오는 명령이다.

 

원래는 센서별로 토픽을 지정했으나, 분류하는 과정이 복잡하고, 오류가 자꾸 발생해서 JSON 형식으로 토픽을 보내도록 했다. 

 

mid는 원래 +"mid_1" 식으로 붙혔는데, 자바에서 파싱할 때는 괜찮았으나 통합모니터링시스템의 Node Js 환경에선

문제가 발생해 "\"mid_1\"" 식으로 수정했다.

 

 

5. 외형 조립 및 발표 준비 

 

조립이야 어렵진 않았다. 플라스틱 케이스에 폼 양면테이프 사용.

 

하지만 발표 준비가 진짜 어려웠는데, 6인의 팀원이 절반 절반 나눠 3인은 프론트엔드 (PC/모바일 웹), 3인은 IoT 파트를 담당해서 진행하다보니 프론트엔드 팀은 IoT를 아예 모르고, IoT 팀은 프론트엔드 파트에 약점이 생겨버릴 수 밖에 없었다.

 발표자가 프론트엔드 팀이였는데, 할 말이 너무 많아 IoT 팀원들이 같이 붙어서 원고 봐주고 설명해줬는데도

말을 줄이자니 이해하기 어려울 것 같고, 그렇다고 넣자니 발표자가 대본 암기하기 어려울 것 같고...

그래서 대본을 들고 올라갔는데 불이 꺼지는 바람에 대본도 보기 힘들었다고 한다. 발표자가 진짜 고생이 많았지..

 

 

6. 대망의 발표 당일

 

02:11:04 부터 보면 된다. 팀원 소개 시간 때 내 역활에 대해서 잘 써 놨는데 너무 떨린 나머지 얼버무리고 말았다. 어휴..

 

 

 

7. 후기

 

 그냥...일주일만 더 빨리 Node Js 포기하고 JSP/Servlet으로 선회할껄 그랬다. 개발 범위 설정과 시간 분배에 성공해서 

남들 프로젝트할 때 미리 끝내고 다른 조 도와주고, 발표준비했던 1차 프로젝트와는 달리, 개발 범위 설정과 시간 분배에

실패했던 것 같다. 멘토의 방향을 잘못 이해하다보니 MQTT 도입도 늦어졌고, 기능 구현도 쉽지는 않았다.

일단 예제도 없고, 심화로 갈려니 정말...머리 터지는 줄 알았다. 

사실 만든 것도 버그 투성이다. ESP8266을 쓴 건 좋은데 너무 불안정하고, 웹서버에서 넘어오는 토픽도 받아질 때도 있고 자기 맘대로 동작한다. 이것저것 코드를 다 집어넣어놔 분리시켜 라이브러리화 시키면 좋은데 C++과 자바의 클래스 구조에는 차이도 있고, 분리해보려는 데 시간이 너무 촉박했다. 

 사실 DB도 1차처럼 내가 좀 봐줬어야 하는데 (기기번호(자동증가 컬럼)으로 식별하기 보단 기기 SN로 구별하는 게 좋은데, 신경 못 쓴 사이에 기기번호로 식별하도록 모든 VO, DAO가 짜여져서 그 부분이 좀 아쉬웠음) 그러질 못했다.

 

운이 좋아 최우수상까지 수상했지만 시간관리 측면에서 참 생각이 많아진 프로젝트였다. 

 

 

 

 

실습 환경 : mariadb, 우분투 리눅스, 아파치 웹 서버, PHP 7.4

실습 보드 : ESP8266 개발 보드 + DHT22 센서

 

설정 간 문제 해결 과정

mariadb 설치 후 sudo mysql -u root 실행 시 Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2) 오류 발생

 

0. 서비스 재실행

sudo service mysql restart 또는 sudo systemctl restart mariadb 입력하여 서비스 재실행

 

1. 서비스 재실행 자체가 실패할 경우 (+삭제 후 실행시 동일증상 발생해도 마찬가지)

/var/lib/mysql 폴더 강제 삭제 후 데이터 재생성 해주기,

cd var/lib/ 입력하여 경로 이동,

sudo rm -r mysql mysql 폴더 강제 삭제(* rm 명령어로 폴더 삭제할 경우 -r 옵션을 rm 명령어 뒤에 붙힌다)

sudo mysql_install_db --user=mysql 

sudo service mysql start 또는 sudo systemctl start mariadb 입력하여 서비스 정상 동작 확인하기

 

 

GET 방식으로 웹서버 전송

받는 측 PHP 파일에서 별도의 수신 확인 응답을 보내지 않기 때문에

시리얼 모니터 상으론 에러코드 -11번이 출력되나 정상적으로 DB에 값이 저장되는 것으로 보임.

//GET 방식으로 웹서버로 전송.

#include <ESP8266HTTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include "DHT.h"
#define DHTPIN D2     // Digital pin connected to the DHT sensor
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);
float h;
float t;
const char* ssid = "";
const char* password = "";

//Your Domain name with URL path or IP address with path
String serverName = "<http://192.168.2.175/test2.php>";

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastTime = 0;
// Timer set to 10 minutes (600000)
//unsigned long timerDelay = 600000;
// Set timer to 5 seconds (5000)
unsigned long timerDelay = 5000;

void setup() {
  Serial.begin(115200); 
  dht.begin();
   WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
   Serial.println("Connecting to WiFi..");
  }
 
  Serial.println("Connected to the WiFi network");
}

void loop() {
  readtemphum();
  
  
  //Send an HTTP POST request every 10 minutes
  if ((millis() - lastTime) > timerDelay) {
    //Check WiFi connection status
    if(WiFi.status()== WL_CONNECTED){
      HTTPClient http;

      String serverPath = serverName + "?temp="+String(t)+"&hum="+String(h);
      
      // Your Domain name with URL path or IP address with path
      http.begin(serverPath.c_str());
      
      // Send HTTP GET request
      int httpResponseCode = http.GET();
      
      if (httpResponseCode>0) {
        Serial.print("HTTP Response code: ");
        Serial.println(httpResponseCode);
        String payload = http.getString();
        Serial.println(payload);
      }
      else {
        Serial.print("Error code: ");
        Serial.println(httpResponseCode);
      }
      // Free resources
      http.end();
    }
    else {
      Serial.println("WiFi Disconnected");
    }
    lastTime = millis();
  }
}

void readtemphum(){
    delay(2000);
   h = dht.readHumidity();
  t = dht.readTemperature();
}
  • POST 방식으로 전송하는 아두이노 코드
#include <ESP8266HTTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include "DHT.h"
#define DHTPIN D2     // Digital pin connected to the DHT sensor
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);
float h;
float t;
const char* ssid = "";
const char* password = "";
const char*  serverName = "<http://192.168.2.175/posttest.php>";
String url = "/post/";
unsigned long lastTime = 0;
unsigned long timerDelay = 5000;

void setup() {
  Serial.begin(115200);
  dht.begin();
  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());

  Serial.println("Timer set to 5 seconds (timerDelay variable), it will take 5 seconds before publishing the first reading.");
}

void loop() {
  readtemphum();
  //Send an HTTP POST request every 10 minutes
  if ((millis() - lastTime) > timerDelay) {
    //Check WiFi connection status
    if (WiFi.status() == WL_CONNECTED) {
      WiFiClient client;
      HTTPClient http;
      // Specify content-type header
      http.addHeader("Content-Type", "application/x-www-form-urlencoded");
      String postData = "temp=" + String(t) + "&hum=" + String(h);
      String address = serverName + url;
      http.begin(address);
      auto httpCode = http.POST(postData);
      Serial.println("전송 데이터 :: " + postData);
      Serial.println(httpCode); //Print HTTP return code
      String payload = http.getString();
      Serial.println(payload); //Print request response payload
      // Free resources
      http.end();
    }
    else {
      Serial.println("WiFi Disconnected");
    }
    lastTime = millis();
  }
}

void readtemphum() {
  delay(2000);
  h = dht.readHumidity();
  t = dht.readTemperature();
}
  • 네트워크 연결 후 5초 뒤 전송
  • 성공한 경우 HTTP 코드 200번 반환 (성공) 연결에 문제 있을 경우 500번 반환(실패)

WEB SERVER 측 코드

https://wikidocs.net/116936 (PHP 3분 핵심 요약집 참고하여 실습)

<?php
function db_get_pdo()
{
    $host = 'localhost';
    $port = '3306';
    $dbname = 'sensor';
    $charset = 'utf8mb4';
    $username = 'ggk_test';
    $db_pw = "";
    $dsn = "mysql:host=$host;port=$port;dbname=$dbname;charset=$charset";
    $pdo = new PDO($dsn, $username, $db_pw);
    return $pdo;
}

function db_select($query, $param=array()){
    $pdo = db_get_pdo();
    try {
        $st = $pdo->prepare($query);
        $st->execute($param);
        $result =$st->fetchAll(PDO::FETCH_ASSOC);
        $pdo = null;
        return $result;
    } catch (PDOException $ex) {
        return false;
    } finally {
        $pdo = null;
    }
}

function db_insert($query, $param = array())
{
    $pdo = db_get_pdo();
    try {
        $st = $pdo->prepare($query);
        $result = $st->execute($param);
        $last_id = $pdo->lastInsertId();
        $pdo = null;
        if ($result) {
            return $last_id;
        } else {
            return false;
        }
    } catch (PDOException $ex) {
        return false;
    } finally {
        $pdo = null;
    }
}

function db_update_delete($query, $param = array())
{
    $pdo = db_get_pdo();
    try {
        $st = $pdo->prepare($query);
        $result = $st->execute($param);
        $pdo = null;
        return $result;
    } catch (PDOException $ex) {
        return false;
    } finally {
        $pdo = null;
    }
}
?>
  • 범용적인 활용을 위해 PDO 방식 사용.
<?php
require_once("inc/db_pdo.php");

$humidity = isset($_POST['hum']) ? $_POST['hum'] : null;
$temperature = isset($_POST['temp']) ? $_POST['temp'] : null;
//$login_name = isset($_POST['login_name']) ? $_POST['login_name'] : null;

// 데이터 저장
db_insert("insert into save (hum, temp) values (:humidity, :temperature)",
    array(
        'humidity' => $humidity,
        'temperature' => $temperature,
    )
);

'Tech' 카테고리의 다른 글

Rocky Linux/Oracle Linux ) Semanage 사용하기  (0) 2022.03.16

Selinux 활성화 상태에선 포트변경이 막혀있기 때문에 (그렇다고 selinux를 꺼버리는 건 보안상 좋지 않으니)

Semanage를 사용해서 포트정보를 확인하고, 정책을 변경해야 한다.

 

리눅스 버전에 따라 semanage 사용 시 command not found 메시지가 뜨는 경우가 있는데,

yum whatprovides semanage 를 입력하여 찾을 수 있다.

명령어, 혹은 패키지명으로 확인할 수 있으며, 설명까지 확인할 수 있다.

여기서 최신버전 패키지명을 복사한 후

Sudo yum install 패키지명 으로 설치하면 완료.

'Tech' 카테고리의 다른 글

아두이노 호환보드와 웹서버간 GET, POST 방식 실습하기  (0) 2022.12.20

 

학원을 다니면서 정보처리기사 실기도 응시하긴 했지만, 아무래도 학원 수업과 같이 준비하니 공부하기가 많이 벅차

결국엔 떨어지고 말았다. 50점을 간신히 넘긴거라 더 아깝기도 했고.

 

그래서 대신 SQLD를 응시하기로 마음 먹고 학원에서 책을 수령했다. 꽤 일찍 수령했지만 학원의 일정 상 바로 수업은 들어가지 않고, 1차 프로젝트가 마무리 된 후 부터 특강을 잡아주었다.

 

 

 

 

나름 일학습병행제로 회사 생활 할 때도 오라클 DB를 배웠었고, 학원 수업에서도 열심히 들어 익숙한 편이였지만, 

아무래도 MS-SQL + Oracle SQL 이 혼재된 형태인지라 책을 풀면서도 많이 어려웠다.

특히나 학원에서 수령한 책이 기출문제 문제은행 도서라 해설, 또는 기초 개념 설명이 아쉬운 게 더 많기도 했고.

 

 

 

SQLD란?

 

K-DATA(한국데이터산업진흥원)에서 주관하는 시험 중 Structured Query Language Developer의 줄임말로,

SQL 개발자를 의미한다. 상위 자격증으로는 SQLP(여기서 P는 Professional의 약자)가 있다.

2013년 부터 민간 자격증에서 국가 공인 민간 자격증으로 승격되었다고 한다.

 

응시료는 작년 기준으로 5만원 정도 냈던걸로 기억한다. 싸지 않은 금액이라 망설여질 수도 있긴 했는데..

떨어저도 공부했다 셈 치자 생각하고 응시했다. 

 

https://www.dataq.or.kr/www/main.do 

 

데이터자격시험

카드결제/계좌이체 환불 환불 요청시 즉시환불

www.dataq.or.kr

 

 

출제 문항은 다음과 같다.  

각 과목별로 과락이 존재하니 그걸 조심해야 한다. 총점 60점 이상에 과목별 40% 이상 득점을 해야 한다.

SQL은 좀 알 거 같은데 용어가 애매하다 싶으면 1과목 과락으로 탈락 할 수 있으니 준비를 해 두는 것이 좋다.

SQLD 시험을 준비하면서 정보처리기사 필/실기의 데이터베이스 과목 준비도 같이 되니 정말 좋았다.

시험 준비 과정

 

1차 프로젝트가 끝나고, 저녁시간에 조금씩 시험에 나오는 부분에 해당하는 문제를 한번 쫙 풀었다.

 

틀린게 많았고, 답지를 봐도 왜? 라는 생각이 드는 문제도 있었다.

이론도 까다로웠지만 쿼리문의 결과를 유추하는 문제나 보기 중 다른 결과가 나오는 쿼리문을 골라내는 게 제일 

힘들었다. 확실히 직접 써 보면서 결과를 확인해보는 것이 좋겠다 싶었다.

 

인터넷에 공개된 준비 자료도 한번 훑어 보았다. 

 

다행히 DB 강사 분이 다 같이 풀이를 해 주면서 열심히 받아 적었고, 따로 질문도 하면서 정리를 했다.

오라클과 MS SQL 과는 차이가 있기 때문에 그 부분을 같이 비교해서 정리도 하고, 구글 검색을 통해 정리하기도 했다.

동일한 기능을 다른 명칭으로 부르기도 하는 부분도 많았는데, 그 부분을 잘 짚어주셔서 도움이 많이 됐다.

 

 

 

시험날 당일

준비물 :: 컴퓨터용 사인팬과 검정색 볼펜, 신분증, 수험표(?)

특히 다른 건 문제가 안 되지만 실물 신분증은 꼭 챙겨 갈 것! 

이거 안챙겨서 시험장까지 왔다가 다시 돌아간 사람이 몇명 있었다..

 

전날 밤에 문제 풀다가 컨디션이 안 좋아 조금 늦게 잤고, 힘들게 일어났다.

시험지 배부를 기다리며 문제를 다시 풀기 보다는 개념이나 용어를 한번 더 봤다.

다행이도 이번 회차 시험이 그리 어렵지 않아 생각보다는 쉽다는 느낌으로 답을 썼고, 주관식 또한 다 채울 수 있었다.

 

 

 

그리고 12월 17일 결과 발표....

 

 

모델링 부분은 확실하게 답을 쓴 게 많아서 그런지 꽤나 득점을 많이 했고,

활용부분에서는 결과를 잘못 유추한 것들이 있어 저런 결과가 나온 것 같았다. 주관식도 하나였나 두개였나 잘못 쓴 게 있었고..

 

앞으로도 더 배워야 겠다는 생각이 들었다. 그래도 정말 증명할 수 있는 게 하나 생긴 건 기분이 정말 좋았다.

 

 

 

 

'학원 수업 관련 > DB' 카테고리의 다른 글

DB Insert 시 특정 값 select + insert하기  (0) 2021.11.02

 

Activity란?

안드로이드의 4대 컴포넌트 (Activity, Serivce, Broadcast Receiver, Content Provider) 중 하나로

어플리케이션이 실행되었을 때 보여지는 화면을 구성하는 역활을 한다.

 

 

 

엑티비티는 다음과 같은 생명주기를 가진다. 어플리케이션이 시작되면 가장 먼저 onCreate()가 호출이 되며,

onCreate() 이전에 추가하는 경우 표시되지 않거나 오류가 발생하는 걸 확인할 수 있을 것이다.

 

하지만 하나의 엑티비티 가지고 어플리케이션을 표현하기엔 무리가 많기에 Intent를 활용하게 된다!

 

Intent란?

하나의 액티비티가 다른 액티비티를 실행시킬 수 있는 메세지 시스템을 의미.

 

특정 액티비티를 콕 찝어 시작시킬 수 있고 (명시적 Intent),

액티비티 간의 데이터 전달 목적으로 사용 할 수 있고,

특정 기능을 하는 액티비티를 시작 시킬 수 있다. (암시적 Intent),

 

메인 액티비티에 카메라와 전화, 서브 엑티비티에 표시할 텍스트를 입력받는 란을 만들고,

 

메인엑티비티에서 입력한 문자열을 표시해줄 TextView와  메인으로 가는 버튼을 만들어 주었다.

 

 

다만 카메라 위치정보 연락처 등의 민감 권한의 경우 메니페스트 파일을 다음과 같이 수정해주어야한다.

<application></application> 상단에 <uses-permission> 태그를 다음과 같이 작성해주었다.

코드는 다음과 같이 작성했다.

버튼에 클릭리스너를 달아주고, 퍼미션 여부를 확인한다. 그런 뒤 권한이 없으면 요청을 보내고, 

승인되어있다면 인자로 주어진 전화번호로 연결되도록 else 문을 작성했다.

 

서브액티비티로 가는 버튼에는 다음과 같이 클릭리스너를 달아주었다. 

getText()의 경우 타입이 Editable이기 때문에 안전하게 ToString()을 사용해서 문자열 형식으로 형변환 시켜주어야 한다.

 

서브 액티비티에서는 getIntent()를 사용해서 넘겨준 값을 받고, 

input이란 이름으로 edt_input의 문자열을 보내주었기 때문에 꺼내올땐 intent.getStringExtra를 통해

꺼내올 수 있다. 

메인 화면으로 돌아가는 버튼에는 finish();를 달아주었다. 

 

문자열이 잘 넘어가는 걸 확인할 수 있다.

민감권한의 경우 다음과 같이 권한을 요청하는 창이 뜬다. 허용된 이후에는 앱을 종료했다가 켜도 권한을 더 이상 요구하지 않는다.

 

 

 

 

 

+ Recent posts