비콘 위치기반 이미지 데이터 송신 프로그램.docx
1.21MB

프로젝트 결과물

프로젝트.zip
2.44MB

 

 

 

 

이미지는 바이너리(binary) 데이터이다.

MySQL은 바이너리 데이터를 저장할 때, BLOB 타입을 사용한다.

BLOP은 Binary Large Object의 약어이다.

BLOP 타입은 소팅이나 INDEX생성은 할 수 없다.

 

 

1. 테이블 추가

 

MySQL을 실행하고, 아래 명령어를 실행한다.

 

mysql> CREATE TABLE Images(Id INT PRIMARY KEY, Data MEDIUMBLOB);

 

MEDIUMBLOB 타입 데이터를 저장할 수 있는 Images 테이블을 생성한다.

BLOB 타입은 indexing을 할 수 없으므로,

INT형 Id 필드를 만들고 PRIMARY KEY로 선언한다.

MEDIUMBLOB 타입에서 이미지는 16MB까지 저장할 수 있다.

이외에도 TINYBLOB(255 Bytes), BLOB(64 KB), LONGBLOP(4GB) 타입이 있다.

 

 

 

2. 소스코드

 

그림 파일 하나를 Images 테이블에 저장하는 소스코드이다.

 

#include <my_global.h>

#include <mysql.h>

#include <string.h>

 

void finish_with_error(MYSQL *con)

{

fprintf(stderr, "%s \n", mysql_error(con));

mysql_close(con);

exit(1);

}

 

int main(int argc, char** argv)

{

// picture.jpg read binary(rb)모드로 파일을 연다.

// 실행파일과 같은 경로에 사진이 있어야 한다.

FILE *fp = fopen("picture.jpg", "rb");

if (fp == NULL) {

fprintf(stderr, "cannot open image file \n");

exit(1);

}

 

// 파일 포인터를 파일의 끝으로 옮긴다.

fseek(fp, 0, SEEK_END);

 

if (ferror(fp)) {

fprintf(stderr, "fseek() failed \n");

int r = fclose(fp);

 

if (r == EOF) {

fprintf(stderr, "cannot close file handler \n");

}

exit(1);

}

 

// 파일의 처음부터 파일 포인터가 가리키는 곳까지의 크기를 flen에 저장

int flen = ftell(fp);

if (flen == -1) {

perror("error occurred");

int r = fclose(fp);

if (r == EOF) {

fprintf(stderr, "cannot close file handler \n");

}

exit(1);

}

 

// 파일 포인터를 파일의 시작으로 옮김

fseek(fp, 0, SEEK_SET);

if (ferror(fp)) {

fprintf(stderr, "fseek() failed \n");

int r = fclose(fp);

 

if (r == EOF) {

fprintf(stderr, "cannot close file handler \n");

}

exit(1);

}

 

// 이미지 데이터를 저장할 배열 동적할당

char* data = (char *) malloc(sizeof(char) * (flen+1));

 

// 이미지 저장 함, 저장된 바이트 수가 size에 반환 됨

int size = fread(data, 1, flen, fp);

if (ferror(fp)) {

fprintf(stderr, "fread() failed \n");

int r = fclose(fp);

if (r == EOF) {

fprintf(stderr, "cannot close file handler \n");

}

exit(1);

}

 

// 파일 닫기

int r = fclose(fp);

if (r == EOF) {

fprintf(stderr, "cannot close file handler \n");

}

 

// MYSQL 구조체 초기화

MYSQL *con = mysql_init(NULL);

if (con == NULL) {

fprintf(stderr, "mysql_init() failed \n");

exit(1);

}

 

// 서버 연결

if (mysql_real_connect(con, "localhost", "user01", "1q2w3e!", "testdb",

0, NULL, 0) == NULL)

{

finish_with_error(con);

}

 

char* chunk = (char *)malloc(sizeof(char) * (2*size + 1));

mysql_real_escape_string(con, chunk, data, size);

 

char *st = "INSERT INTO Images(Id, Data) VALUES(1, '%s')";

size_t st_len = strlen(st);

 

char *query = (char *)malloc(sizeof(char) * (st_len + 2*size + 1));

int len = snprintf(query, st_len + 2*size + 1, st, chunk);

 

if (mysql_real_query(con, query, len)) {

finish_with_error(con);

}

 

mysql_close(con);

exit(0);

}

 

 

char* chunk = (char *)malloc(sizeof(char) * (2*size + 1));

mysql_real_escape_string(con, chunk, data, size);

 

binary data에서 중간에 삽입된 종결문자를 없애는 과정이다.

종결문자에 \, ', ", Ctrl+z 등이 있지만 아래에서는 \만으로 설명한다.

mysql_real_escape_string()함수는 문자열의 종료를 의미하는 '\0' 앞에

\를 붙여 '\\0'으로 만든다.

 

또한 이 함수를 사용함으로써 SQL injection attack도 예방할 수 있다.

(SQL injection attack 참고 : https://opentutorials.org/module/411/3962)

 

\를 붙이는 작업 때문에 최악의 경우 원래의 데이터의 2배짜리 버퍼가 필요하다

따라서 data버퍼 size의 2배 +1 만큼의 길이를 chunk에 할당한다.

 

 

char *st = "INSERT INTO Images(Id, Data) VALUES(1, '%s')";

size_t st_len = strlen(st);

 

쿼리문을 구성하고, strlen 함수를 통해 이 쿼리문의 길이를 구해 st_len에 저장.

 

 

char *query = (char *)malloc(sizeof(char) * (st_len + 2*size + 1));

int len = snprintf(query, st_len + 2*size + 1, st, chunk);

 

최종적으로 MySQL 서버에 보낼 쿼리문을 구성하는 과정이다.

앞서 구했던 '쿼리문의 길이'와 'chunk의 길이'를 합한

'st_len + 2*size + 1'만큼을 동적할당 한다.

그리고 snprintf를 통해서 query버퍼에 st와 chunk를 가지고

이미지 저장을 요청하는 쿼리문을 완성한다.

 

if (mysql_real_query(con, query, len)) {

finish_with_error(con);

}

 

이전까지는 mysql_query() 함수를 통해 데이터를 넣었었다.

mysql_query() 함수는 binary 데이터가 포함된 쿼리를 처리하지 못한다.

여기서는 binary 데이터를 취급하기 때문에 mysql_real_query() 함수를 사용한다.

 

 

 

 

아래 링크를 참고하여 번역 및 수정함 

http://zetcode.com/db/mysqlc/

 

 

다른 참조

http://jidolstar.tistory.com/681

 

http://www.mysqlkorea.com/sub.html?mcode=manual&scode=01&m_no=21872&cat1=22&cat2=596&cat3=606&lang=k



출처: https://www.molllab.com/15 [mollLab]

출처: https://www.molllab.com/15 [mollLab]

'[ 충남인력개발원 ] (2019) > ┗TCP&IP' 카테고리의 다른 글

Uduntu window 통신  (0) 2020.01.13
MYSQL의 모든것  (0) 2020.01.08
프로젝트 분석  (0) 2019.11.29
mysql 더 설치하기 ㅎㅎ...  (0) 2019.11.28
Mysql 리눅스 연동하기  (0) 2019.11.28
블로그 이미지

Or71nH

,