아래는 제가 사용하는 프로그램 소스입니다. 저희가 다른 곳에서 뉴스를 소켓으로 받아서 이를 다시 Mysql로 넣는 프로그램입니다. 소켓 프로그래밍쪽은 다른 곳에서 작성한것을 서버 ip정도만 제가 수정한것이라서 그다지 참고할것은 없고(이것도 원래 바꾸려고 하다가 말았지요) 그냥 Mysql로 C 프로그래밍 하는데 참고정도나 하세요. 참고로 제가 C에 대해서는 그다지 개발경험이 없다는것은 기억을 하시고 보세요. 정규표현식한번 써보려다가 낑낑대고 포기했지요.
먼저 간단한 Makefile
$ cat Makefile
CC=gcc
SOURCE=mysql_yunhap.c
products=yunhap
all : install
install:
gcc -o $(products) $(SOURCE) -lmysqlclient -I/usr/include/mysql -L/usr/lib
위에서 헤더파일과 라이브러리 경로 지정하는것만 알고 있으면 되죠.
$ cat config.h
#define DB_NAME \taejun\ // database name
#define LIST_TABLE \list\ // list table
#define VIEW_TABLE \view\ // view table
#define CATEGORY_TABLE \category\ // category table
#define HOST \111.111.111.111\ // db server ip
#define USER \taejun\ // user name
#define PASSWD \taejun\ // password
#define SVR_TCP_PORT 4000 // server tcp port number
#define SERVER_HOST_ADDR \192.168.10.50\ // server host ip
물론 위에서는 실제 정보 보여주는것이 아니라 제가 바꾼것이지요.
위의 config.h 헤더파일은 아무래도 db명, 사용하는 테이블, 호스트, db접속 사용자 및 비밀번호, 서버 포트등을 헤더파일에 넣어 쉽게 변경할수있도록 한것입니다.
아래 프로그램은 초반부분은 주로 소켓이므로 뒤로 팍 넘어가서 db연결처리하는부분만 보시면 됩니다. 제가 네트웍 프로그래밍 및 C 프로그래밍은 초보 수준이므로 아래에서 문제가 있는 부분을 말해주시면 좋겠요. 솔직히 버퍼 오버플로우나 보안등에 대한 고민까지 제가 간 상황은 아니라서요.
/************************************************************************
* 뉴스 소켓으로 받아서 Mysql db 에 넣는 프로그램 ****
* 다른곳에서 사용하던 것을 제공받아 일부수정
2001. 9. 27 최종수정 문태준
************************************************************************/
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <time.h> // 원소스에서 시간관련 부분 에러생겨 추가했음
#include \mysql.h\ // mysql 기능 추가 위해 필요함
#include \config.h\ // mysql 접속 및 server ip, port
// 상수정의
#define null 0
#define MAX_FILE_SIZE 2000
#define MAX_FRAME_SIZE 1024
#define MSG_SIZE 29
#define ERROR 1
#define TRUE 1
#define FALSE 0
// 소켓관련 변수 설정
// int rcv_data_len;
// short rcv_mbx_chan;
// static char hostname[50];
//int listen_sock,accept_sock,comm_sock;
int accept_sock,comm_sock;
//int comm_flag = 0;
int i, k;
int shut = FALSE;
int retval;
// 기사 필드 구조체
struct {
char req_cmd[1]; // start \S\
char kisa_size[5]; // 기사크기
char yymmddhhmm[10]; // 발행일 (년월일시간분)
char bu_code[2]; // 부서코드 - 사용하지 않음
char bunya[6]; // 발생처 - 사용하지 않음
char section[4]; // 분야 -정치, 경제, 사회, 문화, 체육, 외신, 지방, 기타
char kubun[1]; //긴급구분. 주요기사=1, 일반기사=, 긴급기사=3. 실제 활용안함
}req_msg;
// 소켓 관련 변수
static struct sockaddr_in sock_name;
struct hostent hostentstruct;
struct hostent *hostentptr;
int namelength;
// 기사 관련 변수
char fname[50];
char file_cmd; // start
char file_buf[MAX_FILE_SIZE];
char file_ymdhm[16]; //년월일시분
char file_date[32]; // 년월일시분초
char file_bu_code[2]; //부서코드
char file_bunya[6]; // 발생처
char file_section[16]; // 섹션구분
char file_kubun[8]; // 긴급구분
int su_size;
int su_count;
int section_code;
// 기사 제목 처리 관련 변수
char title_match1[20],title_match2[20];
char *loc;
int title_match;
int change_code(char *section)
{
if(strcmp(section,\정치\)==0)
section_code = 1;
if(strcmp(section,\경제\)==0)
section_code = 7;
if(strcmp(section,\사회\)==0)
section_code = 13;
if(strcmp(section,\외신\)==0)
section_code = 22;
if(strcmp(section,\체육\)==0)
section_code = 27;
if(strcmp(section,\행정\)==0)
section_code = 35;
if(strcmp(section,\지방\)==0)
section_code = 40;
if(strcmp(section,\문화\)==0)
section_code = 51;
if(strcmp(section,\정보통신\)==0)
section_code = 61;
if(strcmp(section,\오피니언\)==0)
section_code = 64;
if(strcmp(section,\기타\)==0)
section_code = 64;
return section_code;
}
int title_check(char *title_match1, char *title_match2)
{
loc = strstr(title_match1,title_match2);
if(loc == NULL)
title_match=0;
else
{
printf(\title : %s \n\,title_match1);
printf(\\%s\ 단어가 들어감\n\,title_match2);
title_match=1;
}
return title_match;
}
/************************************************************************
소켓 연결
************************************************************************/
socket_open()
{
/* open socket 2 : AF_INET, SOCK_STREAM */
if ((comm_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) // socket 디스크립트 할당
{
perror(\socket error\);
exit(1);
}
/* get pointer to network data VAX5는 CLIENT시스템 ADDRESS사용 */
if ((hostentptr = gethostbyname(SERVER_HOST_ADDR)) == NULL)
{
perror(\gethostbyname error\);
if (shut)
{
if (shutdown(comm_sock, 2) < 0)
perror(\shutdown error\);
}
if (close(comm_sock) != 0)
perror(\close error\);
exit(1);
}
/* copy hostent data to safe storage */
hostentstruct = *hostentptr;
/* fill int name & address structure for socket 2 */
/* 서버 주소 형성 */
sock_name.sin_family = hostentstruct.h_addrtype;
sock_name.sin_addr = *((struct in_addr *) hostentstruct.h_addr);
sock_name.sin_port = (unsigned short) htons(SVR_TCP_PORT);
/* 서버의 주소 지정 */
retval = bind(comm_sock, &sock_name, sizeof(sock_name));
if (retval)
{
perror(\bind error\);
close(comm_sock);
wait(5000);
return -1;
}
/* 동시에 클라이언트의 접속 처리 큐의 수 지정 */
retval = listen(comm_sock, 1);
printf(\listen = %d\n\, retval);
if (retval)
{
perror(\listen error\);
close(comm_sock);
return -1;
}
return 0;
}
/************************************************************************
주요작업 처리 - 소켓에서 내용받아서 처리하여 db에 입력작업함
************************************************************************/
db_process()
{
// Mysql API 변수 설정
MYSQL mysql;
MYSQL_RES *res;
MYSQL_ROW row;
//MYSQL_FIELD *field;
//int fields;
int number;
// 기사 입력 관련 변수 설정
int temp_id;
char list_id[12];
char my_year[4], my_month[2], my_date[2];
int year, month, date;
int list_number; // 개별기사번호
char list_paperdate[10];
char list_title[80];
int code_id; // 기사분류 코드
char view_text[32000];
// 질의문 위한 변수 설정
char number_query[200];
char list_query[200];
char view_query[200];
char category_query[200];
// Mysql 질의 및 테이블 이름 설정
char query[32000];
// 변수 선언
FILE *fi;
char fname[50];
char buf[MAX_FRAME_SIZE];
char dir[64], curdate[32], sec[32], url[128], title[128], title2[128], context[32000], *end, context2[32000];
char file_size[5];
int title_size;
char *bufptr, *tmp;
int flen, tval;
time_t tloc;
struct tm *tt;
int j;
// php 외부프로그램 실행위한 변수
char cmd[50];
tloc = time(NULL); // unixtime 반한
tt = localtime(&tloc);
tval = (tt->tm_hour*60+tt->tm_min)*60+tt->tm_sec; // 현재시간 받는 함수인듯. 시분초
if (tval > 65535) tval -= 65535;
// 변수초기화
memset(&file_section,0,16);
memset(&file_size,0,5);
memset(&req_msg,0,MSG_SIZE);
// 소켓에서 첫째줄 읽기 - su_count는 읽은 문자수 반환
su_count = read(accept_sock, &req_msg, MSG_SIZE);
if (su_count < MSG_SIZE)
{
printf(\INTER_MAKE invalid req_msg---> %d\n\n\n\,su_count);
return -1;
}
printf(\get req_msg---> %s\n\, (char *)&req_msg); // 첫줄 출력
strncpy(&file_cmd, &req_msg.req_cmd[0], 1); // 2번째 인자를 첫번째 인자로 세번째인자크기만큼 복사. start
strncpy(&file_size[0], &req_msg.kisa_size[0], 5); // 기사 크기
strncpy(&file_ymdhm[0], &req_msg.yymmddhhmm, 10); // 년월일시분
strncpy(&file_bu_code[0], &req_msg.bu_code, 2); // 부서코드
strncpy(&file_bunya[0], &req_msg.bunya, 6); // 발생처
strncpy(&file_section[0], &req_msg.section, 4); // 분야, 섹션
strncpy(&file_kubun[0], &req_msg.kubun, 1); // 긴급, 구분
su_size = atoi(file_size); // atoi 문자열을 정수로 변환. 기사 size
code_id = change_code(file_section); // 기사분류 숫자로 바꿈
sprintf(file_date, \20%c%c-%c%c-%c%c %c%c:%c%c\,
file_ymdhm[0], file_ymdhm[1], file_ymdhm[2], file_ymdhm[3],
file_ymdhm[4], file_ymdhm[5], file_ymdhm[6], file_ymdhm[7],
file_ymdhm[8], file_ymdhm[9]); // 년월일시분 yymmddhhmm
sprintf(list_paperdate, \20%c%c-%c%c-%c%c\, file_ymdhm[0], file_ymdhm[1],
file_ymdhm[2], file_ymdhm[3], file_ymdhm[4], file_ymdhm[5]); // 년월일
memset(&file_buf, 0, MAX_FILE_SIZE);
memset(&buf, 0, MAX_FRAME_SIZE);
///////// 제목, 본문 처리
su_count = recv(accept_sock, &buf, MAX_FRAME_SIZE, 0); // 둘째줄 읽기
if (su_count <= 0) return;
i = su_count;
bufptr = strchr(buf, \n\); //특정문자 첫번째 위치 찾고 포인터 반환
*bufptr = \0\;
bufptr++; // 본문 위치로 이동
tmp = strstr(buf, \ \); // buf에 \ \ 처음 문자열 위치 검색
if (tmp != NULL)
*tmp = \0\; // 제목 마지막으로 이동하여 문자열로 표시
title_size = tmp - buf; // 제목길이
strcpy(title, buf); // title에 제목 입력
flen = &buf[0]-bufptr; // 제목처음 - 제목마지막
snprintf(context,su_count-79,\%s\,bufptr);
while(1) // 계속 떠서 자료받아들임
{
su_count = recv(accept_sock,&buf, MAX_FRAME_SIZE, 0); //자료받기
if (su_count > 0) // 소켓에서 자료를 받아들이는동안
{
strncat(context,buf,su_count);
i += su_count;
// 기사 본문 받아서 db에 입력
if(i == su_size) // su_size 기사크기 기사를 모두 받은 경우임
{
strncpy(&req_msg.req_cmd, \1\, 1);
su_count = send(accept_sock, &req_msg, MSG_SIZE, 0); //받았다는것보냄
/************************************************************************
db에 입력
************************************************************************/
//기타 기사 빼기
if(code_id == 64)
{
printf(\기타 코드와 연관되므로 집어넣지 않음\n\);
break;
}
if(title_check(title,\주요\) == 1)
{
printf(\기사 입력 제외함\n\);
break;
}
if(title_check(title,\오늘의 일정\) == 1)
{
printf(\기사 입력 제외함\n\);
break;
}
if(title_check(title,\오늘의 증시일정\) == 1)
{
printf(\기사 입력 제외함\n\);
break;
}
if(title_check(title,\세계의 날씨\) == 1)
{
printf(\기사 입력 제외함\n\);
break;
}
if(title_check(title,\내일의 경기\) == 1)
{
printf(\기사 입력 제외함\n\);
break;
}
if(title_check(title,\밀라노프로젝트\) == 1)
{
printf(\기사 입력 제외함\n\);
break;
}
if(title_check(title,\이주의 산행\) == 1)
{
printf(\기사 입력 제외함\n\);
break;
}
if(title_check(title,\연합시론\) == 1)
{
printf(\기사 입력 제외함\n\);
break;
}
if(title_check(title,\오 늘 의\) == 1)
{
printf(\기사 입력 제외함\n\);
break;
}
if(title_check(title,\뉴욕-업종\) == 1)
{
printf(\기사 입력 제외함\n\);
break;
}
if(title_check(title,\도자기엑스포\) == 1)
{
printf(\기사 입력 제외함\n\);
break;
}
if(title_check(title,\외국환시세\) == 1)
{
printf(\기사 입력 제외함\n\);
break;
}
// db 시작
mysql_init(&mysql);
// db 연결 - *mysql host user passwd db port unix_socket client_flag
if(!mysql_real_connect(&mysql,HOST,USER,PASSWD,DB_NAME,0,(char *)NULL,0))
{
printf(\connet error. error no: %d\n%s\n\,mysql_errno(&mysql),mysql_error(&mysql));
break;
//exit(1);
}
// title, context(본문) 문자열에 escape 문자 추가
mysql_real_escape_string(&mysql,list_title,title,title_size);
mysql_real_escape_string(&mysql,view_text,context,su_size-80);
/***** 개별기사번호 처리 ************/
sprintf(number_query,\select max(a.list_number) as number from %s a, %s b where b.code_id=%d and a.list_paperda
te = \%s\ and a.list_id=b.list_id\,LIST_TABLE,CATEGORY_TABLE,code_id,list_paperdate);
if(mysql_real_query (&mysql, number_query, strlen(number_query)) )
{
printf(\number_query error. error no: %d\n%s\n\,mysql_errno(&mysql),mysql_error(&mysql));
break;
//exit(1);
}
res = mysql_store_result(&mysql);
if(res) // NULL이 아니므로 반환된 레코드가 있는 경우
{
row=mysql_fetch_row(res);
// null이 아닐 경우 atoi 함수를 이용하여 문자로 나온 결과를 숫자로 바꿈
if(row[0])
list_number = atoi(row[0])+1;
else
list_number = 1;
}
else // res가 NULL이므로 에러가 생긴 경우
{
printf(\mysql_store_result_error. error no: %d\n%s\n\,mysql_errno(&mysql),mysql_error(&mysql));
break;
//exit(1);
}
// id 계산. 년월일 각자 받아서 문자열을 숫자로 변환
sprintf(my_year, \20%c%c\,file_ymdhm[0],file_ymdhm[1]);
year=atoi(my_year);
sprintf(my_month,\%c%c\,file_ymdhm[2],file_ymdhm[3]);
month=atoi(my_month);
sprintf(my_date,\%c%c\,file_ymdhm[4],file_ymdhm[5]);
date=atoi(my_date);
temp_id = (year-1980)*33554432 + month*2097152 + date*65536 + code_id*512 + list_number;
sprintf(list_id,\y%d\,temp_id);
/***** 목록 list 처리 ************/
sprintf(list_query,\insert into %s values(\%s\,\%d\,\%s\,\%s\,\%s\,\n\,\n\)\,
LIST_TABLE,list_id,list_number,list_title,list_paperdate,file_date);
if( mysql_real_query (&mysql, list_query, strlen(list_query)) )
{
printf(\list query error. error no: %d\n%s\n\,mysql_errno(&mysql),mysql_error(&mysql));
break;
//exit(1);
}
printf(\n==================== 기사 입력 ================\n\);
printf(\기사 섹션 : %s - %d\n\,file_section,code_id);
printf(\list query : %s\n\,list_query);
//list_id = mysql_insert_id(&mysql); // 위에서 입력한 최종 id 구함
/***** 본문 view 처리 ************/
sprintf(view_query,\insert into %s values(\,\%s\,\%s\,\n\)\,
VIEW_TABLE,list_id,view_text);
if( mysql_real_query (&mysql, view_query, strlen(view_query)) )
{
printf(\view query error. error no: %d\n%s\n\,mysql_errno(&mysql),mysql_error(&mysql));
break;
//exit(1);
}
/***** 기사분류 category 처리 ************/
sprintf(category_query,\insert into %s values(\,\%s\,\%d\,\y\)\,
CATEGORY_TABLE,list_id,code_id);
if( mysql_real_query (&mysql, category_query, strlen(category_query)) )
{
printf(\category query error. error no: %d\n%s\n\,mysql_errno(&mysql),mysql_error(&mysql));
break;
//exit(1);
}
printf(\view query : %s\n\n\,view_query);
printf(\category_query : %s\n\,category_query);
printf(\==================== 기사 입력 완료 ================\n\n\n\n\);
mysql_free_result(res); // 메모리 해제
mysql_close(&mysql); // db 연결 끊기
/************* Mysql 입력하기 끝 ***************/
break;
// su_size 기사크기만큼 모두 다 받았으므로 빠져나가서 다시 자료받음
} // if(i == su_size) loof 소켓에서 자료를 모두 받아들였음
}
else // if (su_count > 0) loof 소켓에서 자료를 받아들인게 없는 경우
{
printf(\INTER_MAKE receive data ERROR OCCURS\n\n\);
strncpy(&req_msg.kisa_size[0],\00000\, 5); //기사 size 00000 로 세팅
strncpy(&req_msg.req_cmd, \1\, 1); // S -> 1로 바꿈
printf(\value of req_msg-->%s\n\n\, &req_msg);
su_count = send(accept_sock, &req_msg, MSG_SIZE, 0); //기사 못 받았다는것 보냄
break;
}
} // while loop end
}
/************************************************************************
main 프로그램
************************************************************************/
main()
{
retval=socket_open(); // 소켓열기
if (retval) // 소켓 open 에러 처리
{
printf(\INTER_MAKE socket을 open할수없읍니다\n\n\);
exit(0);
}
while(1) // 소켓이 열렸을 경우
{
namelength = sizeof(sock_name);
/* 클라이언트 접속 요청을 처리 - 새로운 소켓 디스크립터 할당 */
accept_sock = accept(comm_sock, &sock_name, &namelength);
if (accept_sock == -1) // error
{
perror(\client accept error\);
continue;
}
db_process(); // 주요처리 프로그램
close(accept_sock); // 자식 프로세스의 소켓 닫기
}
close(comm_sock); // 서버 소켓 닫기
}
|