비콘 위치기반 이미지 데이터 송신 프로그램.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

,

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

소프트웨어 6단계 개발 절차

1. Requirement 

2. Analysis           요구사항 정의서

3. Design            설계 시작

4. Implement       프로그램 짜기

5. Test                에러잡고 디버깅   이게 길게걸림

6. Deployment     사용법 

 

 

 

2017.09.22 프로젝트의 분석과 설계_rev2.pdf
0.47MB

설계하는법

 

버퍼에서 

sprintf(buf,"%d", n);

sscanf("buf,"%lf",&d);

블로그 이미지

Or71nH

,

뭔가 더추가해야한다

위에 설치를 완료하고 시작 하면 된다

 

 

 

이건 주말에 복스임..

 

 

 

 

들어간다음

 

ㄴshow databases ;

로 확인을하고

 

데이터 배이스를 만들어보자 

 

이제 테이블도 만들고 

 

엔터 지면 -> 이 생김

mysql> create table test (name char(10), 
    -> age int,
    -> pet char(10)
    -> );

 

에러가 떳다 

데이터 베이스가 정해지지 않아서 ,,

use test;

mysql> create table test (name char(10),  age int, pet char(10) ); 

를 하고 다시쳐준다

 

이제 글좀 써넣어 보자

 

insert into test values ('me', '20', 'cat');

만들고 이제 불러와보자

 

 

 

mysql.c 에 만들어주고

#include <stdio.h>
#include <mysql/mysql.h>

int main()
{
	MYSQL mysql;
	MYSQL_RES *myresult;
	MYSQL_ROW row;
	unsigned int num_fields;
	unsigned int num_rows;
	char*string_query;
	mysql_init(&mysql);
	mysql_real_connect(&mysql,"localhost","root","1234","test",0,NULL,0);
	string_query="select*from test \n";

	mysql_query(&mysql,string_query);
	myresult=mysql_store_result(&mysql);
	while(row=mysql_fetch_row(myresult))
		printf("%s\t%s\n",row[0],row[1]);
	mysql_free_result(myresult);
	mysql_close(&mysql);
	return 0;
}

 

 

 

설치된 경로 찾기 

 

 

 

 

패키지  찾고 

dpkg -l | grep mysql | grep dev

 

 

이름으로 검색

 

dpkg -L libmysqlclient-dev

 

 

요기 찾앗다 

 

 

 

C파일 만든곳 들어가준 다음에 

 

 

mysql.c 아까 친것이 보이네요

 

 

 

gcc mysql.c -I/usr/include/mysql/ -Wall -g -lmysqlclient -g

 

언제나 에러와 함께하지만 

당황하지 말고 경고니깐 실행은 됨

하 세그맨 테이션 오류라니!

 

 

그럼 관리자로 시작해버려

강제로 됫움 ㅎㅎ.

됫어 그럼

블로그 이미지

Or71nH

,

일단은 mysql 설치부터 해야한다

보면 위에 

sudo apt-get install mysql-server mysql-client

이거 쳐주고 띄어쓰기 주의!!

 

Y 만 눌러주면 설치 잘해줌

 

 

 

 

다시하면 설치되있어서 이리뜸

 

 

이제 소두를 이용해서 mysql 를 실행하자

 

 

 

database 들중에서 

 

use mysql;

을 사용하여 들어간다!

 

 

그리고 좀봄

저기 유저가 보인다 저기로그인 정보가 있을것이다

함불러와 보자 

 

정말 보기힘들지마 

authentication_string 이 암호다!

게불러오자

난 암호가 설정해줘서 이렇게 암호가 있다고 나온다

 

암튼 암호 바꾸기 시작해보자 

 

update user set authentication_string=password('1234') where user='root';

 

바뀜

리플레쉬 한번 해주고

 

flush privileges;

 

나가자

이거나 exit;

 

이거  quit;

암거나 둘다됨

 

그럼 이제 인터넷이 연결될 수 있게

 

하 /....  파일부터 찾자 안나오더라 한번에 

mysql 에서 mysqld.cnf를 찾아야한다

찾움

참고 위치

cd /etc/mysql/mysql.conf.d/

 

 

이제 vi 로 들어가서 좀 지우자

#붙이면 주석 처리되서

실행이 안되게 된다

 

수정이 안된다...

 

 

관리자 권한으로 해야한다

 

sudo vi mysqld.cnf

 

 

 

수정하고 그럼 이제  다시시작

 

sudo service mysql restart

 

 

이제 준비는 완료하엿다

mysql 관리자 권한만 수정하면 

 

하고싶은데로 할수 있다

 

 

 

mysql 들어가서 

 

grant all privileges on *.* to root@localhost identified by '1234';

권한 설정 하는거임 

 

 

끝 쓰면됨

 

 

 

 

 

블로그 이미지

Or71nH

,

 

                            센서                 

                 0~1023    |

server --------------- client

   |       1         0....*     |

   |                            |

   |                          stdoot

  DB

 

양방향 서버 

 

클라이언트 소켓을 

 

하프 클로우스 로 상대방이 끊었을떄 나옴

fgets() 엔터키ㄹ떄까지 기다림

 

 

 

이제 서버를 만들고 받을 준비를 해보자

 

 

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


#define BUF_SIZE 100
#define MAX_CLNT 256

void * handle_clnt(void * arg);
void send_msg(char * msg, int len);
void error_handling(char * msg);

int clnt_cnt=0;
int clnt_socks[MAX_CLNT];
pthread_mutex_t mutx;

int main(int argc, char *argv[])
{
	int serv_sock, clnt_sock;
	struct sockaddr_in serv_adr, clnt_adr;
	int clnt_adr_sz;
	pthread_t t_id;
	if(argc!=2) {
	printf("Usage : %s <port>\n", argv[0]);
	exit(1);
	}

	pthread_mutex_init(&mutx, NULL);
	serv_sock=socket(PF_INET, SOCK_STREAM, 0);

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

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

	if(listen(serv_sock, 5)==-1)
		error_handling("listen() error");

	while(1)
	{
		clnt_adr_sz=sizeof(clnt_adr);
		clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr,&clnt_adr_sz);

		pthread_mutex_lock(&mutx);
		clnt_socks[clnt_cnt++]=clnt_sock;
		pthread_mutex_unlock(&mutx);

		pthread_create(&t_id, NULL, handle_clnt, (void*)&clnt_sock);
		pthread_detach(t_id);
		printf("Connected client IP: %s \n", inet_ntoa(clnt_adr.sin_addr));
	}
	close(serv_sock);
	return 0;
}

void * handle_clnt(void * arg)
{
	int clnt_sock=*((int*)arg);
	int str_len=0, i;
	char msg[BUF_SIZE];

	while((str_len=read(clnt_sock, msg, sizeof(msg)))!=0)
		send_msg(msg, str_len);

	pthread_mutex_lock(&mutx);
	for(i=0;i<clnt_cnt; i++)
	{
		if(clnt_sock==clnt_socks[i])
		{
			while(i++<clnt_cnt-1)
				clnt_socks[i]=clnt_socks[i+1];
			break;
		}
	}
	clnt_cnt--;
	pthread_mutex_unlock(&mutx);
	close(clnt_sock);
	return NULL;
}

void send_msg(char * msg, int len) 
{
	int i;
	pthread_mutex_lock(&mutx);
	for (i=0; i<clnt_cnt; i++)
		write(clnt_socks[i], msg, len);

	pthread_mutex_unlock(&mutx);
}

void error_handling(char * message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

그리고 

접속할 유저들을 모집해보자

 

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

#define BUF_SIZE 100
#define NAME_SIZE 20 

void * send_msg(void * arg);
void * recv_msg(void * arg);
void error_handling(char * msg);

char name[NAME_SIZE]="[DEFAULT]";
char msg[BUF_SIZE];

int main(int argc, char *argv[])
{
	int sock;
	struct sockaddr_in serv_addr;
	pthread_t snd_thread, rcv_thread;
	void * thread_return;
	if(argc!=4) {
		printf("Usage : %s <IP> <port> <name>\n", argv[0]);
		exit(1);
	}

	sprintf(name, "[%s]",argv[3]);
	sock=socket(PF_INET, SOCK_STREAM, 0);

	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)
		error_handling("connect() error");

	pthread_create(&snd_thread, NULL, send_msg, (void*)&sock);
	pthread_create(&rcv_thread, NULL, recv_msg, (void*)&sock);
	pthread_join(snd_thread, &thread_return);
	pthread_join(rcv_thread, &thread_return);
	close(sock);
	return 0;
}

void * send_msg(void * arg) 
{
	int sock=*((int*)arg);
	char name_msg[NAME_SIZE+BUF_SIZE];
	while(1)
	{
		fgets(msg, BUF_SIZE, stdin);
		if(!strcmp(msg,"q\n")||!strcmp(msg,"Q\n"))
		{
			close(sock);
			exit(0);
		}
		sprintf(name_msg,"%s %s", name, msg);
		write(sock, name_msg, strlen(name_msg));
	}
	return NULL;
}

void * recv_msg(void * arg)
{
	int sock= *((int*)arg);
	char name_msg[NAME_SIZE+BUF_SIZE];
	int str_len;
	while(1)
	{
		str_len=read(sock, name_msg, NAME_SIZE+BUF_SIZE-1);
		if(str_len==-1)
			return (void*)-1;
		name_msg[str_len]=0;
		fputs(name_msg, stdout);
	}
	return NULL;
}

void error_handling(char * message)
{
	fputs("message", stderr);
	fputc('\n', stderr);
	exit(1);
}

되긴 됫는데 복잡하게 체팅이 보여 내가보낸것도 나한테오고 ,,

 

수정좀 해야겟움

블로그 이미지

Or71nH

,