반응형

Linux CentOS 7 : 방화벽 설정 입문

알게된 배경

 리눅스를 사용하는 대부분의 이유는 서버로 사용일 것이다. 그러면 항상 붙는 설정이 포트 설정과 방화벽 설정이다. 그래서 어쩔 수 없이 알아야 한다. 다만, 방화벽이 CentOS 7 으로 넘어와서 이전과 차이점이 있었다. 그래서 이전 버전이라면 추가 검색이 필요하다.


설정 커맨드

# tcp 방식 80포트 개방목록 추가
firewall-cmd --permanent --zone=public --add-port=80/tcp

# tcp 방식 80포트 개방목록 삭제
firewall-cmd --permanent --zone=public --remove-port=80/tcp

# 방화벽 재실행
firewall-cmd --reload


 아직 입문 수준이라 주로 사용하는게 위의 내용이 대부분이다. --이후에 붙는 내용들은 옵션이기 때문에 옵션 규칙만 맞는다면 순서는 상관없다.


주의 사항

 옵션 구분자'-'가 몇개인지 확인해야 한다. 종종 몇몇 블로그에서는 옵션 구분자를 하나로만 적는 경우가 있다. 방화벽에 대해 더 자세한 설명은 공식문서나 정리된 블로그를 참조하자.


참고자료

방화벽 공식 문서(영문)

한글로 일부 정리한 블로그

JAVA커뮤니티 글



반응형
반응형

gcc C++ : 유닉스 라이브러리 만들기 입문

알게된 배경

 리눅스 환경에서 처음에는 간단한 프로그램을 제작을 했지만, 점차 커기게 되자 상당히 많은 양의 파일들이 한폴더에 어지럽게 있자 더 이상 모듈화를 하지 않으면 코드관리가 안될만한 상황이 되어 라이브러리 작성법에 대해서 공부하게 되었다.


염두해야 될 것

 윈도우 개발환경과 달리 리눅스환경의 경우 gcc의 옵션을 활용하는 방법을 알아야 했다. 그리고 편하게 하려면, makefile을 활용해야 하고, 더 편하게 makefile을 만들기 위해서는 makefile을 어느정도 알고 있는 상태에서 cmake를 사용할 줄 알아야 한다.


테스트 샘플 코드

// ~/lib_test/include/sample.h
#pragma once
#inlcude <iostream>

class Sample
{
public:
    Sample(void);
    ~Sample(void);

    void print(void);
};
// ~/lib_test/src/sample.cpp
#include "../include/sample.h"

using namespace std;

Sample::Sample(void)
{}
Sample::~Sample(void)
{}
void Sample::print(void)
{
    cout << "hello snupy?!" << endl;
}
// ~/lib_test/main.cpp
#include "include/sample.h"

int main(int argc, char* argv[])
{
    Sample sam;
    sam.print();
    return 0;
}



정적 라이브러리

 파일 확장자는 a(Archives의 앞글자)이며, object(.o) 파일과 큰 차이는 없다. 정적라이브러리를 통해서 빌드된 프로그램에 정적라이브러리가 포함되기 때문에 프로그램의 용량이 커지는 특징이 있다. 라이브러리에 수정할 내용이 있어서 수정하게 되면, 프로그램을 다시 빌드해야 하는 단점이 있다.


만드는 방법

# ~/lib_test/ 에서 실행할 경우
g++ -c ./src/sample.cpp -o ./obj/sample.o
ar rc ./lib/libsample.a ./obj/sample.o

 첫 줄은 sample.cpp를 sample.o 로 빌드가 되며, 두번째 줄은 libsample.a로 정적 라이브러리로 만들어준다. ar의 명령어는 아카이브(Archives)의 앞의 두글자를 딴 것이다. 또한 리눅스에서는 파일이름앞에 lib를 붙여야 나중에 실행 파일을 빌드할 때 lib로 인식을 하니 붙여줘야 한다.

 만약 해당 코드에 C++11이상 같은 표준라이브러리을 사용한다면, 오브젝트(.o)파일로 빌드할 때 -std=c++11 같은 옵션을 추가해주어야 한다.


링크된 실행파일 만들기

# ~/lib_test/ 에서 실행할 경우
g++ -o test main.cpp -Llib -lsample

 위의 명령어는 main.cpp라는 소스코드를 test라는 이름으로 빌드를 하게 된다. 이때 lib라는 폴더에 있는 sample이라는 이름의 라이브러리를 참조하라는 명령이 된다. 앞에서 작성한 libsample.a 파일을 sample이라는 라이브러리로 인식을 하게 된다.

 정적 라이브러리는 빌드 이후에는 실행파일에 포함이 되기 때문에 빌드이후 sample.a가 없어도 실행이 된다.


공유 라이브러리

 윈도우의 dll(동적 라이브러리)와 비슷한 개념이다. 때문에 공유 라이브러리를 동적 라이브러리라 부르는 곳도 있다. 확장자는 .so(Share Object의 각 앞글자 머리) 공유 라이브러리의 가장 큰 특징은 정적 라이브러리와 달리 특정 공유 라이브러리 파일만 교체를 해도 수정된 내용이 적용이 된다. 즉, 실행파일을 재 빌드할 필요가 없다(물론 파일이 삭제되거나 추가되면 어쩔 수 없이 재컴파일해야 한다).

 이러한 특징으로 나온 개념이 플러그인 이다(라고 많은 책이나 참고자료가 언급한다).


만드는 방법

# ~/lib_test/ 에서 실행할 경우
g++ -fPIC -c ./src/sample.cpp -o ./obj/sample.o
g++ -shared -o ./lib/libsample.so ./obj/sample.o

 첫줄은 고정된 파일로 컴파일을 하여 오브젝트 파일로 빌드를 한다. 이후 두번째 명령에서는 공유 오브젝트 파일을 생성한다. 여기서는 간단히 확장자를 so로 작성했지만, 보통 프로그램 버전을 관리 할 경우 so.1.0.0 이런식으로 숫자를 뒤에 붙여서 관리를 한다. 또한 -Wl 옵션을 사용하여 추가 옵션을 붙이는 경우가 많다(입문자에게는 이러한 부분이 오히려 진입장벽을 높이는 결과가 되는 것 같다)


링크된 실행 파일 만들기

# ~/lib_test/ 에서 실행할 경우
g++ -o test main.cpp -Llib -lsample

 앞의 링크된 실행파일을 만드는 것과 큰 차이가 없다. 하지만, 이렇게 만들어진 실행파일은 바로 실행할 수 없는데, 이유는 정적 라이브러리와 달리 공유 라이브러리는 실행파일에 포함이 안되어 있기 때문에 실행에 필요한 파일을 알려줘야 한다. 여기서 -L옵션은 빌드할때만 사용되는 라이브러리 경로이다.


 다만, 윈도우즈의 동적 라이브러리인 dll의 경우 보통 실행파일이 있는 폴더와 하위 폴더, 그리고 환경변수에 등록된 폴더에서 실행에 필요한 dll파일이 있는지 찾아서 실행한다.


 반면 리눅스 환경에서는 그냥 환경변수만 찾아 본다(어떤이는 이를 버그라 생각을 한다). 따라서 환경변수에 있는 폴더 경로에 공유 라이브러리를 복사하는 방법과 환경변수를 만들어서 등록해줘야 된다.

 때문에 실행하기 전에 ldd 명령어를 통해 의존성 검사로 파일을 실행하는데 필요한 공유 라이브러리가 연결되어 있는지 확인 할 수 있다.

# ~/lib_test/ 에서 실행할 경우
ldd ./test

 이렇게 확인한 의존성 검사에서 "not found"가 없어지도록 해야 실행이 가능해진다.

 공유 라이브러리를 이용해 배포했을 경우 해당 프로그램을 유지 및 삭제 관리를 할 때 어떻게 할 것인지도 고민을 해야 한다.


환경변수 추가 등록

export LD_LIBRARY_PATH = [라이브러리절대경로]


 환경변수를 통해서 라이브러리 위치를 찾을 수 있다면, ldd로 검사했을 때 not found가 더 이상 보이지 않을 것이다. 실행했을 프로그램의 결과가 보이면 성공적으로 라이브러리를 생성하고 실행을 해본 것이다.


 하지만, LD_LIBRARY_PATH라는 환경변수는 디버그용(배포 전단계의 실행 테스트)에서 사용할 것을 권하지 배포하는 방법으로는 적합하지 않다.


보충해야 될 내용

 여기까지 혼자서 테스트 해보는데 성공했다면, gcc에 대한 옵션에 대해서 추가로 살펴봐야 한다. 당연한 소리지만, 테스트 결과 -l 옵션을 여러번 사용해서 여러개의 라이브러리를 참조하는 것이 가능하다. 또한 옵션을 사용하는 경우가 많으니 gcc 옵션에 대해서도 어느 정도 숙지를 하고 있어야 한다.


참고자료

우분투 환경에서 C언어로 배우는 리눅스 프로그래밍(서적)

옵션에 대한 정리(영문)

옵션에 대해 한글로 자주 사용하는 것만 정리(간혹 오역도 보인다)



반응형
반응형

리눅스 C : TCP 소켓 프로그램

알게된 배경

 라즈베리 파이를 위한 소캣 프로그램을 만들다 보니 어쩔 수 없이 TCP와 같은 소켓 프로그램을 제작하게 되었다. 소켓 프로그램의 경우 대부분 표준화가 되어 있으며, 구현하는 절차가 거의 정해져 있다. 때문에 이해를 했다 하더라도 외우고 있는건 무리기 때문에 기록을 남긴다.


사전에 염두 해야 할 점

 C와 C++이 일반적으로 빠른 이유는 운영체제와 거의 직접적으로 맞닿아서 작동이 된다는 점이다. 심지어 운영체제가 없는 마이크로프로세서 분야에서도 C가 사용되고 있다. 즉, 하드웨어나 운영체제의 영향을 많이 받기 때문에 당연히 윈도우와 리눅스간 코드는 차이가 있다.

 하나 더 알아야 할 것은 리눅스, OS X, FreeBSD 등 윈도우를 제외하고는 대부분은 유닉스 기반이라 소켓 코드가 거의 같다(게다가 컴파일러도 거의 비슷하다).


소스코드

 일반적으로 에코서버 코드가 기본이지만, 여기서는 스트림을 전송하거나 수신하는 코드는 제외한다.


서버

#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

void errorHandl(char* msg)
{
    puts(msg);
    exit(1);
}

int main(int argc, char* argv[])
{
    int serv_sock;
    int clnt_sock;
    struct sockaddr_in serv_addr;
    struct sockaddr_in clnt_addr;
    socklen_t clnt_addr_sz;

    if(argc != 2)
    {
        printf("Usage : %s <port>\n", argv[0]);
        exit(1);
    }
    // 서버 TCP 소켓 생성
    serv_sock = socket(PF_INET, SOCK_STREAM, 0);
    if(serv_sock == -1)
         errorHandl("socket() error");

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(atoi(argv[1]));

    if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1)
        errorHandl("bind() error");

    // serv_sock 다음 인수는 최대 대기중인 클라이언트 수
    if(listen(serv_sock, 5) == -1)
        errorHandl("listen() error");

    clnt_addr_sz = sizeof(clnt_addr);
    clnt_sock = accept(serv_sock, (struct sockaddr*) &clnt_addr, &clnt_addr_sz);
    if(clnt_sock == -1)
        errorHandl("accept() error");

    // 이제 소켓을 통해서 전송할 작업을 작성하면 된다.
    // 생략

    // 클라이언트/서버 순서대로 스트림을 닫느다.
    close(clnt_sock);
    close(serv_sock);

    return 0;
}


클라이언트

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

void errorHandl(char* msg)
{
    puts(msg);
    exit(1);
}

int main(int argc, char* argv[])
{
    int sock;
    struct sockaddr_in serv_addr;
    if(argc != 3)
    {
        printf("Usage : %s <IP> <port>\n", argv[0]);
        exit(1);
    }
    // TCP 소켓 설정
    sock = socket(PF_INET, SOCK_STREAM, 0);
    if(sock == -1)
         errorHandl("socket() error");

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
    serv_addr.sin_port = htons(atoi(argv[2]));

    if(connect(sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1)
        errorHandl("connect() error");

    // 여기서 전송이나 수신하는 내용을 작성함
    // 생략

    // 소켓 스트림 닫음
    close(sock);

    return 0;
}



반응형
반응형

Linux CentOS 7 : sudo 권한 설정

알게된 배경

 Ubuntu의 경우 위험성이 높은 root 계정을 아예 못 쓰게 막아놓고 sudo 라는 권한 명령어를 통해서 root의 권한을 부여받아서 사용이 가능하다. 하지만, centOS의 경우 기본적으로 sudo의 권한은 root만이 갖고 있다.

 이 때문에 여러 개발자들이 접속해야 하는 서버의 경우 root 계정을 사용 못하게 하면서 사용하게 하기 위해서는 sudo 명령어를 사용할 수 있는 권한을 설정해 줘야 한다.


설정파일

기본적으로 설정파일의 권한 설정은 "- r-- r-- ---"(440)로 돠어 있다. 때문에 수정하기 위해서는 먼저는 쓰기 권한을 설정한 다음에 파일을 수정해야한다.

ls -al /etc/sudoers
# 퍼미션 상태확인하고나서..
chmod u+w /etc/sudoers
vi /etc/sudoers



가능하면 몰아서 수정하자.

# 생략
root    ALL=(ALL)    ALL
# 여기에 추가를 하면 된다.



 파일을 수정하나 다음에는 다시 위의 모드로 설정을 되돌려 놓아야 sudo 명령어를 사용할 수 있다. 즉, sudo 명령어를 사용할 때마다 위의 파일을 읽어 오는듯 하다.

chmod u-w /etc/sudoers


설정하는 방법

특정 사용자가 sudo 사용

예시)lemi 계정

lemi    ALL(-ALL)    ALL


특정 그룹 사용자가 sudo 사용

예시)devel 그룹

%devel    ALL=(ALL)    ALL


패스워드 생략하여 sudo 사용

예시)lemi 계정과 devel 그룹

lemi    ALL=(ALL)    NOPASSWD: ALL
%devel    ALL=(ALL)    NOPASSWD: ALL



참고자료

블로그


반응형
반응형

Linux CentOS 7 : ssh-key remote login (아이디/비밀번호 없이 원격 로그인)

알게된 배경

 ssh-key는 리눅스 외에도 널리 사용되고 있는 git에서도 사용되고 있는 방식으로 먼저 접해보긴 했지만, 리눅스에서의 로그인에도 사용된다는 것을 알게 되었다. 아이디, 패스워드 로그인 방식은 통신과정에서 위의 아이디와 패스워드가 노출될 가능성이 존재한다. 물론 ssh 터미널 자체가 상당한 보안이지만, 더욱 견고하게 만들기 위해 등장하게 되었다.

 통신 내용을 두개의 짝을 가진 키를 이용해서 암호화 하기 때문에 해킹하기 더 어려워진다.


ssh-key 생성

 bash에서 ssh-keygen만 입력 해도 자동으로 현재 사용중인 계정폴더에 .ssh 폴더를 생성하고 그안에 키까 쌍으로 생성이 된다. 물론 생성과정에 private 키 안에다가 비밀번호를 추가로 넣는것도 가능하다.


생성시 입력되는 절차는 키생성 위치(기본 ~/.ssh/), 개인키 비밀번호 생성(그대로 엔터로 넘어갈 경우 없음), 생성한 비밀번호 확인, 절차를 거치면 2개의 키가 쌍으로 생성된다.


옵션을 통해서 key를 생성할때 비트수도 조정할 수 있다.


 생성된 파일 2개중에 뒤에 ".pub"가 붙은 파일은 공개키(public key)라 부르고 다른 하나는 개인키(private key)라 부른다. 공개키는 암호화 할때 사용되고, 개인키는 복호화 할때 사용된다. 개인키 보관에 주의 하도록 하자.


서버에 공유키 넣기

 비교적 높은 보안수준의 ssh-key 덕분에 리눅스에서는 ssh-key로 자동 로그인 하는 기능이 존재한다. 계정 폴더 .ssh/ 폴더에 authorized_keys 파일안에 앞에서 생성한 공유키의 내용을 넣으면 된다. 초기에 넣는 방법은 여러방법이 있으니 바음에 드는 방법을 사용하여 넣자. 여기서는 scp를 이용하여 넣겠다. 파일명이 복수인 만큼 누적해서 생성할 수 있다.

예시)

scp ~/.ssh/id_rsa.pub hg@192.xxx.xxx.xxx:~/.ssh/authorized_keys


 위의 올바르게 경우 192.xxx.xxx.xxx라는 호스트에 hg 계정의 /home/hg/.ssh/authorized_keys로 복사하라는 의미이다. 틀린것이 없다면, 기존 패스워드를 묻고 맞는 패스워드를 입력하면 복사가 진행된다.


로그인 옵션 변경

 높은 수준의 보안을 요구하는 곳에서는 원격 로그인을 할 경우 아이디와 패스워드 입력방식을 아예 막기도 한다. 이러한 경우 로그인 옵션을 변경해 줘야한다. 다만, 주의 할 점은 아이디/비밀번호 로그인을 막을 경우 키를 분실하게 될 경우 로그인할 방법이 없기 때문에 신중히 고려해야 한다.

vi /etc/ssh/sshd_config

아래 항목을 주로 설정하는 방식이고 사실 자신의 입맛이나 정책에 맞게 설정을 하자. 일반적으로는 주석처리 되어 있다. (영어가 조금 되는 사람(?)은 값의 이름만 읽어봐도 대략 어떤 내용인지 짐작이 될 것이다.)

# ssh-key로 자동 로그인
PubkeyAuthentication yes
# ssh-key 자동 로그인 경로 설정
AuthorizedKeyFile  .ssh/authorized_keys
# 아이디 패스워드 로인인 옵션 no로 하면 처은 원격 접속시 비밀번호로 로그인을 할 수 없게 된다.
PasswordAuthentication no
# ssh-key로그인 시도에 대해서 답변 메시지를 보낼지 여부
ChallengeResponseAuthentication no

옵션을 변경하였다면, sshd를 다시 시작하면 적용이 된다.

service sshd reload


이제 다시 접속할때 패스워드를 묻지 않는다면, 성공적으로 설정이 된 것이다.


주의사항

 CentOS 7 한정으로 폴더 권한이 ~/.ssh/는 700, authorized_keys 파일은 600으로 되어야 동작이 된다. 라즈비안의 경우 상관이 없는 것으로 확인 되었다.


참고자료

블로그: 비밀번호 막는 방법(영문)

생활코딩: ssh-key 설정하기

블로그: ssh-key 와 옵션 설명


반응형
반응형

Linux CentOS 7 : 사용자 계정 추가

알게된 배경

 협업 환경에서 리눅스라는 운영체제는 다수의 사용자 환경을 제공하기 때문에 이를 이용해서 작업환경을 만들 수 있다.

 각 명령어의 기본적으로 자세한 사용법을 알고 싶다면, 그냥 명령어만 입력을 하면, 사용방법에 대해서 설명을 해준다.


그룹 추가하기

명령어는 "groupadd"이다. 만약 devel이라는 그룹을 추가한다면, 뒤에 적어주면 된다. 우분투의 경우 명령어가 다르니 주의 하도록 하자.

예시)

groupadd devel


계청 추가하기

 명령어는 "useradd"이다. 만약 앞에서 생성한 devel 그룹에 lemi라는 계정을 추가할 경우 -g 옵션을 사용해서 추가해줘야 한다. 옵션 식별자 바로 뒤의 키워드는 옵션 값이 되므로 이를 주의 해서 입력하자. 그룹명이 먼저이나 계정명이 먼저이나 상관은 없다.

예시)

useradd -g devel lemi


계정 비번생성

 root 계정에서 "passwd lemi"를 입력하면, lemi에 대한 패스워드를 새로 생성하는 것을 확인할 수 있다. 이 명령어의 경우 그냥 입력할 경우 현재 로그온 되어 있는 계정의 패스워드를 재설정하려 하기 때문에 주의가 필요하다.

예시)

passwd lemi

 계정 비번이 활성화 되면, 이제 외부에서도 로그인을 할 수 있게 된다.


참고자료

블로그: 리눅스 계정관련 명령 모음

제타위키: 리눅스 계정 생성

게시판: 사용자 계정 패스워드 변경


반응형
반응형

Linux CentOS 7 : Open JAVA 설치하기

알게된 배경

 일반적으로 Linux를 사용할 경우 서버 구축을 하게 되는 경우가 많은데, 특히 웹 서버의 경우 JAVA기반의 웹 앱을 사용하는 경우가 많다. 따라서 JAVA의 설치는 거의 필수라 볼 수 있다.

 JAVA는 ORACLE JAVA와 OPEN JAVA 2가지가 존재한다. 과거에는 안정적인 성능을 위해서는 ORACLE JAVA를 추천을 많이 했었으나 요즘에는 성능차이가 적다. 특히 CetnOS의 경우 open JAVA가 기본 설치 JAVA이다.

 또한 서버에서는 주로 실행을 하기 때문에 JRE만 설치되어 있는 경우도 있기 때문에 이러한 점을 확인해야 한다.


JDK 버전확인

rpm(패키지 관리자)로 jdk 항목을 먼저 확인한다. 또한 jre를 키워드로 입력하여 확인을 할 수 있다.

rpm -qa | grep jdk


저장소 패키지 목록 확인

 yum을 사용하여 설치가능한 항목을 살펴보자. 만약 이미 설치되어 있는 버전과 버전 차이가 없다면, JDK 삭제와 설치를 할 필요가 없다.

yum list java*jdk-devel


JDK 삭제

 앞에서 확인한 항목의 버전이 낮을 경우 삭제한다. 이글이 작성된 시기에는 jdk-1.8까지 나왔으며, 기본적으로는 jdk-1.7이 설치되어 있다. 최신버전을 설치하기 위해 yum remove 명령어를 사용하여 삭제하자.

yum remove java-1.7.0-openjdk-*


JDK 설치

저장소 패키지 목록이 확인한 패키지를 설치하면 된다. 패키지 이름이 길기 때문에 오타에 주의 하거나 "*"를 이용해서 작성하도록 하자. 기본적으로 JDK는 JRE에 의존하기 때문에 JDK를 설치하면, JRE도 설치가 된다.

yum install java-1.8.0-open*.x86_64


JDK 설치 확인

 버전확인 명령어를 실행해서 정상적으로 설치되었는지 확인하면 된다.

java -version
javac -version


참고자료

제타위키 : jdk 목록확인과 설치

블로그 : jdk 제거하기


반응형
반응형

Linux CentOS 7 : MariaDB 문자 설정

문자설정 배경

 MySQL 시절부터 기본설정이 Latin으로 되어 있어서 한글을 입력할 경우 깨지는 경우가 있었다. 때문에 이러한 문제점을 해결하기 위한 문자셋 설정이 필요하다. 현재 전세계 언어를 지원하는 가변 문자셋으로 utf8를 거의 표준처럼(그리고 잠정적인 표준) 사용하고 있기 때문에 이 설정으로 해야 한다.


문자셋 확인

 MariaDB로 로그인이 된상태에서 status를 입력하면 문자셋을 확인할 수 있다. 과거에는 기본적 설정으로 Latin으로 주로 되어 있었는데 요즘에는 server, client 일부만 Latin으로 설정되어 있다.


기본문자셋 설정

 대부분 인터넷에 있는 설정을 확인을 해보면 /etc/my.cnf 파일에서 [mysqld]항목을 수정하도록 되어 있다. 하지만, 해당 파일일을 내용을 보면 [mysqld]항목이 아예 없고 대신 /etc/my.cnf.d 폴더에서 설정파일들을 읽어도록 되어 있는 것을 확인 할 수 있다.

 따라서 이제는 /etc/my.cnf.d/ 항목중에서 적합한 파일을 수정해야 한다. 주로 server쪽 문자셋을 수정해야 하므로 /etc/my.cnf.d/server.cnf 항목을 수정하려고 열어보자. 이 파일안에 우리가 수정하고자 하는 [mysqld]를 찾을 수 있다.

vi /etc/my.cnf.d/server.cnf

파일에서 [mysqld]밑에 문자셋 설정을 추가한다.

# 생략
[mysqld]
init_connect="SET collation_connection=utf8_general_ci"
init_connect="SET NAMES utf8"
character-set-server=utf8
collation-server=utf8_general_ci
# 생략


 문자셋 설정을 하고 나서 MariaDB를 재시작하자.

systemctl restart mariadb


주의 : 종종 재시작이 안되는 경우가 있는데, 이럴경우 침착하게 방금수정한 설정을 삭제한뒤 다시 시도해 본다. 다시 시도했을 때 정상작동되는 경우 오타가 있을 가능성이 크다.

참고자료

 대부분 자료는 각 설정 항목마다 기본문자셋을 설정하지만, 현재는 그럴 필요가 없다.

블로그 : 우분투 환경에서 MariaDB 문자셋 설정

블로그 : CentOS 환경에서 MariaDB 문자셋 설정


반응형
반응형

Linux Ubuntu 16.04 LTS : Ctrl + Space 한영 전환 해제

문제증상

 분명 텍스트 입력키 설정에는 super + space가 변환키로 설정되어 있음에도 불구하고 Ctrl + space도 한/영전환이 되는 문제점이 있다. 이는 우분투 16.04 초기에 입력기가 fcitx로 변하면서 발생한 문제점이다. 문제는 이러한 문제로 통합개발툴의 주 단축키중 하나가 이렇게 언어변환기능으로 인해 사용 못하는 경우가 발생된다. 또한 16.04.2에서도 완전히 해결이 안되었다.


해결방법

 우분투 우측 상단에 키보드 혹은 태극마크를 클릭하여 "설정"을 선택한다. 창이 하나 뜨면, 해당 창에서 "전역 설정"탭을 선택한다.

 입력기 전환 부분을 보면 이 문제의 원흉인 Ctrl + space가 입력되어 있는 걸 볼 수 있다. 다른 키로 바꿔주자. "입력기 사이에 스크롤을 위한 단축키 활성"은 체크를 해제 한다. 한자문화권에서 한글은 사용하지 않는 기능이다.


추가 메모

한/영키로 한영전환 하기

 설정 --> 키보드 --> 바로가기 --> 자판입력 에서 이전 입력 소스전환을 'backspace' 키를 누르면 사용안함으로 전환이 된다. 이후 '구성키'를 '오른쪽 Alt'로 설정한다음에 '다음 입력 소스로 전환'에서 '오른쪽 Alt'키를 누르면 'Multi_key'로 입력이 되면서 '한/영'키로 한영 전환을 할 수 있게 된다.


참고자료

블로그: 초기 우분투 16.04에서 발생한 한글 설정 문제 해결방법을 다룸

반응형
반응형

STL C++ : vector 중복원소 제거

알게된 배경

 한대의 관리 PC에서 여러대의 디바이스 리눅스 계열 운영체제에 접속하는 디바이스 IP 리스트를 관리하기 위해서는 중복으로 접속을 하면 안되기 때문에 중복 검사하는 알고리즘이 필요 하게 되었었다. 일단 이 디바이스 정보들은 vector에 읽어놓은 상태이다(list를 사용하지 않은 이유는 일반적으로 디바이스 정보는 초기에만 설정을 해주고 나머지는 주로 읽기 때문에 이러한 구성을 선택하였다).

 기존의 수많은 STL 관련 서적들에서는 주로 숫자로 된 원소만 정렬하기 때문에 과연 실무에서 응용이 될지 의문이 들었었는데, 프로젝트를 하다 보니 응용을 하게 되어 다시 정리하게 되었다.


디바이스 리스트의 중복 검사

 일반적인 방법은 디바이스 정보중에 구분이 가능한 유니크(unique)한 요소로 비교하여 중복이 될 경우에는 바로 삭제하면 좋겠지만, vector에서 비교 도중에 삭제할 경우 index가 변경되는등 예상지 못하는 상황이 발생된다(그리고 코드도 복잡해진다).


 때문에 안전한 방법 생각한것은 다음과 같다.


1. 중복 검사중에는 중복으로 판된된 vector의 index만 따로 뽑아서 다른 vector에 저장을 해놓는다.


 이부분은 상황에 따라서 로직을 만들면 된다. 여기서는 잘 알려진 방법인 버블 정렬 하는 방식으로 비교하되 같은지 여부를 체크한다. 이 경우 2개의 중복이 있을 경우 문제가 안되지만, 3개 이상의 중복 원소가 있을 경우에는 문제가 생긴다. 때문에 이를 보완하기 위해서 2, 3단계들을 추가로 진행하는 것이다.


2. 중복 index가 있는 vector는 int같은 숫자 원소를 갖고 있기 때문에 (대부분 STL 교재의 예제에 있는)일반적으로 중복 검사 알고리즘으로 제거를 한다.


3. 중복 검사가 끝난 index들을 재 정렬을 한다.


4. 3에서 정렬한 vector의 index를 읽어서 제거를 한다. 이때 index가 큰 순서대로(배열의 뒤에서 부터) 제거를 한다.


 vector가 뒤에서 줄어들기 때문에 index가 바뀌는 일도 없고, 데이터 삭제시 이동되는 위치가 다르기 때문에 연산량도 줄어들게 된다.


STL vector 중복 제거

#include <vector>
#include <algorithm>
#include <string>

using namespace std;

struct deviceinfo
{
    string hostname;
    // 기타 요소
};

vector<int> checkOverlap(const vector<deviceinfo> &devVec)
{
    // 중복되는 원소가 보이면, 해당 index를 indexVec에 넣어주는 알고리즘을 구현한다.
    // 여기서는 devVec의 구조체 안에 hostname이 string을 비교한다고 가정한다.
    vector<int> indexVec;
    auto it = devVec.begin();    // auto는 C++11이상에서 사용
    for(int i=0; i<devVec.size(); ++i)
    {
        for(int j=i+1; j<devVec.size(); ++j)
        {
            if(0 == it[i].hostname.compare(it[j].hostname))
                indexVec.push_back(j);
        }
    }
    return indexVec;
}

void rmOverlap(vector<deviceinfo> &devVec)
{
    vector<int> indexVec = checkOverlap(devVec);

    // index중에서 중복되는 부분을 제거
    sort(indexVec.begin(), indexVec.end(), less<int>() );
    vector<int>::iterator pos;
    pos = unique(indexVec.begin(), indexVec.end() );
    indexVec.erase(pos, indexVec.end() );

    // 중복이 제거된 index를 내림차순으로 정렬
    sort(indexVec.begin(), indexVec.end(), less<int>() );
    // 디바이스 vector에서 중복 index부분을 제거
    pos = indexVec.begin();
    for(; pos != indexVec.end(); ++pos)
    {
        devVec.erase(devVec.begin() + (*pos));
    }
}

일반적으로 알려있는 부분은 이미 다른 사람(과 교재)에서 많이 검중이 되었기 때문에 이를 응용할 경우 비교적 안전하다. 중간에 삭제 삽입이 쉬운 리스트로 중복 검사를 한뒤에 vector로 옮겨서 사용하는 방법도 방법중 하나가 된다.


참고자료

블로그: 중복제거에 대해 간략히 나옴(설명은 없음)


추가수정(2017.6.7)

반응형

+ Recent posts