메시지큐를 이용한 프로그램에대해 질문을 드립니다....
글쓴이: lhs8421478 / 작성시간: 금, 2013/04/26 - 3:52오후
안녕하세요 C언어를 공부하는 사람입니다 ...
메시지큐를 이용해서 리스트 조회 프로그램을 만드는중인데요...
server 쪽에서 자꾸 문제가 발생하네요...
우선 소스코드 입니다
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "msg_header.h" void list_init(list_buf_t **head); //링크드 리스트 초기화 int list_insert(FILE *file, list_buf_t **head); //리스트 삽입 void list_all_print(list_buf_t **head); //리스트 프린트 int list_search(msg_buf_t *msg, list_buf_t **head); //리스트 검색 int msg_receive(int msgq_receive_id, msg_buf_t *msg); int main() { int msg_prio; int msgq_receive_id; int res; list_buf_t *list_head; msg_buf_t msg; res = 1; list_head = NULL; list_init(&list_head); msgq_receive_id = msgget(MSGQ_KEYSEND, IPC_CREAT | PERMISSION); //msgq생성 if (msgq_receive_id == -1) { printf("메시지 큐 생성 실패\n"); exit(1); } while (res == 1) { //서버가 계속 가동 되도록 설정 memset(msg.mtext, 0x00, MAX_LENGTH); res = msg_receive(msgq_receive_id, &msg); if (res == -1) { printf("메시지가 없습니다 \n"); res = 1; continue; } list_search(&msg, &list_head); } if(msgctl(msgq_receive_id, IPC_RMID, 0) == -1){ // Remove msgq perror("msgq remove failed"); exit(1); } return 0; } void list_init(list_buf_t **head) { FILE *file; file = fopen("list.txt", "r"); if (file == NULL) { perror("file open error!\n"); exit(1); } while (feof(file) == 0) { list_insert(file, head); } fclose(file); list_all_print(head); } int list_insert(FILE *file, list_buf_t **head) { list_buf_t *tmp_buf; list_buf_t *new_buf; new_buf = (list_buf_t *)malloc(sizeof(list_buf_t)); if (new_buf == NULL) { perror("메모리 부족\n"); exit(1); } if (0 < fscanf(file, "%s %d %s %s %s ", new_buf->name, &new_buf->age, new_buf->rrn_num, new_buf->address, new_buf->phone_num)) { if (*head == NULL) { new_buf->next = NULL; *head = new_buf; } else { tmp_buf = *head; new_buf->next = tmp_buf; *head = new_buf; } } return 0; } void list_all_print(list_buf_t **head) { list_buf_t *ptr; if (*head == NULL) { printf("no data!\n"); return; } for (ptr = *head; ptr != NULL; ptr = ptr->next) { printf("======================================\n"); printf("이름 : %s \n", ptr->name); printf("나이 : %d \n", ptr->age); printf("주민번호 : %s \n", ptr->rrn_num); printf("주소 : %s \n", ptr->address); printf("전화번호 %s \n", ptr->phone_num); printf("======================================\n"); } } int list_search(msg_buf_t *msg, list_buf_t **head) { list_buf_t *ptr; int char_to_int; ptr = *head; while (ptr != NULL) { switch(msg->search_code) { case 1: if (strcmp(msg->mtext, ptr->name) == 0) { printf("dddd\n"); break; } case 2: char_to_int = atoi(msg->mtext); if(char_to_int == ptr->age) { printf("dddd\n"); break; } case 3: if(strcmp(msg->mtext, ptr->rrn_num) == 0) { printf("dddd\n"); break; } case 4: if(strcmp(msg->mtext, ptr->address) == 0) { printf("dddd\n"); break; } case 5: if(strcmp(msg->mtext, ptr->phone_num) == 0) { printf("dddd\n"); break; } } ptr = ptr->next; } return 0; } int msg_receive(int msgq_receive_id, msg_buf_t *msg) { int indentifier; indentifier = msgrcv(msgq_receive_id, msg, sizeof(msg_buf_t), 0, IPC_NOWAIT); if (indentifier == -1) { sleep(1); return -1; } printf("\n---> search_code: %ld content: %s\n", msg->search_code, msg->mtext); return 1; }
구조체는 헤더 파일에 따로 정의를 해놔서
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <string.h> #include <sys/stat.h> #include <errno.h> #define MSGQ_KEYSEND (key_t)1111 #define MSGQ_KEYREAD (key_t)2222 #define PERMISSION 0777 #define MAX_LENGTH 255 typedef struct _msg_buf { int search_code; char mtext[MAX_LENGTH]; }msg_buf_t; typedef struct _list_buf { char name [20]; int age; char rrn_num[20]; char address[40]; char phone_num[20]; struct _list_buf *next; }list_buf_t;
이렇게 하고 코딩을 하는중입니다.
현재 문제점은 list_search함수에서 자꾸 Segmentation fault가 납니다...
이것저것 건드려봐서는 strcmp(msg->mtext, ptr->name)에서 ptr때문에 자꾸 저러는거 같은데...
이걸 어찌 처리 해야될지 도무지 모르겠습니다 ㅜㅜ
도움 부탁 드립니다.
Forums:
search 구현입니다.
//
일단. search 부분을 별도로 분리'해봤습니다.
기존 소스는 거꾸로 값을 넣던데요.
이건 똑바로 값을 넣습니다.
둘다. 방식의 차이일 뿐 이라서... 상관은 없다고 생각합니다.
단지. 제가 보기 편하게 만들어봤습니다.
search는 이걸로 확인하고. msgrcv()와 msgsnd()는 별도로 올려볼 생각입니다. ㅇ_ㅇ;;
http://www.devpia.com/Maeul/Contents/Detail.aspx?BoardID=50&MAEULNO=20&no=910138&ref=910138&page=1
파일이 첨부 안되서. 데브피아 링크로 대체합니다.
----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.
매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.
각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com
msg_rcv() msg_snd() 구현
//
http://www.devpia.com/Maeul/Contents/Detail.aspx?BoardID=50&MAEULNO=20&no=910139&ref=910138&page=1#Contents910139
자세한 내용은 문서를 참고 해보세요. ㅇ_ㅇ;; 두가지가 나뉜 상태로 테스트해서 데이터는 검증 되었습니다.
전송후에 데이터를 잃는 문제등은 제가 확인하지 못했습니다.
//
유닉스 시스템 프로그래밍 SVR4 한빛 미디어를 보고 만들었습니다.
----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.
매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.
각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com
감사합니다 !
감사합니다 ㅜㅜ
공부를 더욱 해봐야겠어요 ㅠㅠ
아직 많이 부족한거 같네요...
SEGV라면 디버거를 쓰셔야죠 디버거를 쓰면 간단하게
SEGV라면 디버거를 쓰셔야죠
디버거를 쓰면 간단하게 해결 됩니다
흠.. 주소값을 이리저리 찍어보다 알게 되었는데요....
위 와일문에서 list_head의 주소값을 계속 찍어주다가
msg_receive함수에서 메시지를 하나 읽어 오면 갑자디 list_head의 주소값이 변경이 되어 버리네요...
이유를 알고 싶은데 도무지 모르겠네요 ㅠㅠ
첨부된 링크에 파일을 실행해 보시면
이렇게 각 주소값이 보여집니다.
해당 주소값을 하나씩 찍어 보면서. 어디로 변경 되는지 확인해 보시면 알 수 있을거 같습니다.
----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.
매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.
각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com
답변 감사합니다..
드디어 문제가 되는곳을 발견했습니다 ㅠㅠ
제가 쓰던 구조체 변수 msg가 시스템 메모리 영역대에 잡혀서 문제를 일으키고 있었습니다 ㅜㅜ
msg를 포인터화 하여 malloc함수를 통해 메모리를 힙영역대로 옮기니 문제 없이 돌아갑니다.
도움 주셔서 감사했습니다 ㅠㅠ
음 ..
답은 아니고.. 여러번 질문을 올리셨는데.. 아직 해결 방법을 찾지 못하신 듯 하여..
주제넘지만 문제를 해결하기 위한 접근 방법에 대해 한 말씀 드리고자 합니다.
일단 꼭 기억하셔야 하는 거는 기계는 정직하다는 겁니다. 내가 시키지 않은 일은 하지 않습니다.
자신의 의도와 다른 이상한 결과가 나왔다고 생각할지 모르겠지만..
실제로는 기계에게 그렇게 움직이도록 이미 명령이 내려진 상태라는 거죠.
잘못된 결과가 출력되는 데에는 반드시 그렇게 되기 위한 조건이 있습니다.
화면에 나온 결과로부터 그 조건들을 하나씩 클리어 해가면, 결국 문제가 되는 조건을 발견할 수 있게 되는거죠.
디버깅이란게.. 결국은 논리적인 추론을 하나씩 검증해 내는 지루한 작업의 반복입니다.
전에 답글 달았던 건데, 아래 글을 예로 들어 보겠습니다.
http://kldp.org/node/137575
간단히 요약하면 파일에서 A 를 읽어, 메모리에 A 를 저장하고, A 를 화면에 출력하려고 했는데 B 가 출력되었다.. 가 되겠군요.
B 가 출력된 결과로 부터 왜 B 가 출력되게 되었는지, 단계적으로 발생할 수 있는 조건들을 나열해 봅니다.
트리 구조가 되는데, 거기서 발생 가능성이 높은 것부터 차례로 검증을 해서 소거해 나가면, 결국은 문제의 원인에 다다르게 됩니다.
다행히도 이 경우에는 첫번째 노드에서 바로 문제가 해결되었죠.
이 문제를 다른 사람에게 설명해서 해결하려고 한다면, 처음 요약한 것 같이 사실 관계를 명확히 할 수 있는 구체적인 서술/근거가 필요합니다.
- 하고자 하려는 일과 실행 환경
- 내가 구현한 (또는 시도한) 방법
- 화면에 표시된 결과 (또는 실행 결과)
위 세가지가 구체적으로, 코드/화면 첨부해서 제시되어야 합니다. (버그 레포트와 비슷)
자세한 건 아래 링크를 참조해 보세요.
http://wiki.kldp.org/wiki.php/%C3%CA%BA%B8%C0%DA%C4%DA%B3%CA#s-4
사실 간단한 문제이고 소스도 짧은데, 왜 사람들이 답변을 안 하고 있을까 생각해 보면..
저 '구체적인 서술' 이 불충분하기 때문이고, 문제를 해결하기 위해서는 질문하신 분과 스무고개 놀이를 해야 하기 때문입니다.
물론 질문하신 분이 어느 정도 수준에 도달해 있다는게 입증된 상태라면, '전원 코드는 꼽았는지..?' 라는 질문부터 시작하지 않아도 되겠지만..
어쨌든 계속해서 스무고개를 해야 한다는 사실은 변하지 않습니다.
그만큼 시간을 투자할 가치가 있는 문제가 아니라면, 답글을 달지 않겠죠.
어쨌든 질문을 읽는 사람들이 원하는 건..
하나씩 건너 뛰고 읽는것 같네요.. 라던가.. segfault 떨어지는데, strcmp 에서 죽는거 같네요.. 같은 추측이 아니라..
송신/수신부의 구체적인 실행 로그나.. segfault 떨어져서 core 뜯어 보니.. 몇번째 라인에서 ptr 에 잘못된 값이 들어가 있습니다.. 와 같은 구체적인 사실 진술, 근거입니다.
음.. 위에 역추적 얘기를 했는데, *nix 에서 디버깅은 주로 메시지를 출력하는 방법으로 이루어집니다.
코드에 디버깅 메시지를 적절하게 꼼꼼히 다는 것도 좋고, assert 를 활용하는 것도 괜찮습니다.
NDEBUG 가 define 되면 assert 코드들은 모두 코드에서 제거되니까요.
printf 같은 경우도 다음과 같은 식으로 코드를 달아 두면, 간단히 디버깅 메시지를 제거할 수 있습니다. http://kldp.org/node/137652 참조
별도로 logging 함수 만들어서, 파일 또는 stdout 으로 빼는거 한 번 만들어 보세요. 두고 두고 써먹게 될겁니다.
그리고 또 하나는 gdb 와 같은 디버거를 이용하는 겁니다. 이건 코드밥 먹는 사람이면 필수로 챙겨야 하는 연장입니다.
gdb core dump 등으로 검색해 보시면 무얼 해야 하는지 알 수 있을겁니다.
간단히.. 쉘에서 ulimit -c unlimited 라고 치고나서 프로그램을 실행하면.. core 파일이 생길거고..
'gdb 실행파일 core' 라고 입력 한 후에..
bt, frame 숫자, info args, info locals, print *ptr 정도의 명령이면 충분히 문제를 추적할 수 있습니다.
-- edited
본문과 직접적인 연관이 있는 부분은 제가 간과한 부분이 있고, 불필요하다 생각되어 정리했습니다.
아래 bushi 님 답글 참고하세요.
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
답변 감사합니다^^
아직 제가 스킬이 많이 부족해서 이러한 문제가 자꾸 생기는거 같네요 ㅠㅠ
문제점을 찾고 편법인거 같지만 처리를 했습니다..
msg라는 구조체 변수가 저장된 메모리 영역대가 아무리 봐도 시스템 메모리를 건드리는거 같아 힙메모리 역영대로
돌려 버렸습니다....
일단 처리는 했는데 또 무슨 문제가 생기게 될지 모르겠네요 ㅠㅠ
음 ..
아래 bushi 님 댓글 참고하세요.
msgsnd, msgrcv 에서 buffer 범위를 벗어난 영역에 접근하고 있습니다.
msgrcv 에서는 overflow 가 발생합니다.
코딩 연습할 때에는, 확실한 근거를 바탕으로 문제를 규명하고 그 문제를 해결할 수 있는 방법을 사용하는 습관을 들이시는게 좋습니다.
편법은 시간이 부족하거나 손가락이 아프거나 코딩하기 귀찮을 때 써먹는거지 문제를 덮는 용도로 쓰면 안 됩니다.
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
넵.. 더욱 많은 연습이 필요할것 같아요....
아직은 많이 미숙해서 ....
더욱 많은 연습과 공부가 필요할것 같아요 ....
typedef struct _msg_buf {
흠...
아직 잘 몰라서 그러는데요...
msgq 구조체에서 인식하기 위해서 왜 long타입을 사용하는 것인가요?
int타입을 사용하면 안되는건가요??
댓글 달기