메시지큐를 이용한 프로그램에대해 질문을 드립니다....

lhs8421478의 이미지

안녕하세요 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때문에 자꾸 저러는거 같은데...

이걸 어찌 처리 해야될지 도무지 모르겠습니다 ㅜㅜ

도움 부탁 드립니다.

shint의 이미지

//
일단. 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

shint의 이미지

//
http://www.devpia.com/Maeul/Contents/Detail.aspx?BoardID=50&MAEULNO=20&no=910139&ref=910138&page=1#Contents910139

자세한 내용은 문서를 참고 해보세요. ㅇ_ㅇ;; 두가지가 나뉜 상태로 테스트해서 데이터는 검증 되었습니다.
전송후에 데이터를 잃는 문제등은 제가 확인하지 못했습니다.

//
유닉스 시스템 프로그래밍 SVR4 한빛 미디어를 보고 만들었습니다.

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

lhs8421478의 이미지

감사합니다 ㅜㅜ

공부를 더욱 해봐야겠어요 ㅠㅠ

아직 많이 부족한거 같네요...

익명 사용자의 이미지

SEGV라면 디버거를 쓰셔야죠
디버거를 쓰면 간단하게 해결 됩니다

lhs8421478의 이미지

	while (res == 1) {		//서버가 계속 가동 되도록 설정
		memset(msg.mtext, 0x00, MAX_LENGTH);
		res = msg_receive(msgq_receive_id, &msg);
		printf("%p\n", list_head);
		printf("%s\n", list_head->name);
		if (res == -1) {
			printf("메시지가 없습니다 \n");
			res = 1;
			continue;
		}
		list_search(&msg, &list_head);
	}

위 와일문에서 list_head의 주소값을 계속 찍어주다가
msg_receive함수에서 메시지를 하나 읽어 오면 갑자디 list_head의 주소값이 변경이 되어 버리네요...
이유를 알고 싶은데 도무지 모르겠네요 ㅠㅠ
shint의 이미지


이렇게 각 주소값이 보여집니다.
해당 주소값을 하나씩 찍어 보면서. 어디로 변경 되는지 확인해 보시면 알 수 있을거 같습니다.

head       - 0022FF68
*head      - 00000000
&*head     - 0022FF68
*&head     - 0022FF68
&head      - 0022FDA0
&(*head)   - 0022FF68
*(&head)   - 0022FF68
 
head       - 0022FF68
*head      - 00000000
&*head     - 0022FF68
*&head     - 0022FF68
&head      - 0022FD84
&(*head)   - 0022FF68
*(&head)   - 0022FF68
 
          head - 0022FF68 003E6E80
222222222  head - 0022FF68 003E6E80
222222222  head - 0022FF68 003E6E80
head       - 0022FF68
*head      - 003E6E80
&*head     - 0022FF68
*&head     - 0022FF68
&head      - 0022FDA0
&(*head)   - 0022FF68
*(&head)   - 0022FF68
 
head       - 0022FF68
*head      - 003E6E80
&*head     - 0022FF68
*&head     - 0022FF68
&head      - 0022FD80
&(*head)   - 0022FF68
*(&head)   - 0022FF68
 
======================================
이름 : 신우섭1 
나이 : 36 
주민번호 : 번호1 
주소 : 주소1 
전화번호 전화번호1 
======================================
======================================
이름 : 신우섭2 
나이 : 37 
주민번호 : 번호2 
주소 : 주소2 
전화번호 전화번호2 
======================================
======================================
이름 : 신우섭3 
나이 : 38 
주민번호 : 번호3 
주소 : 주소3 
전화번호 전화번호3 
======================================

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

lhs8421478의 이미지

드디어 문제가 되는곳을 발견했습니다 ㅠㅠ
제가 쓰던 구조체 변수 msg가 시스템 메모리 영역대에 잡혀서 문제를 일으키고 있었습니다 ㅜㅜ

msg를 포인터화 하여 malloc함수를 통해 메모리를 힙영역대로 옮기니 문제 없이 돌아갑니다.

도움 주셔서 감사했습니다 ㅠㅠ

ymir의 이미지

답은 아니고.. 여러번 질문을 올리셨는데.. 아직 해결 방법을 찾지 못하신 듯 하여..
주제넘지만 문제를 해결하기 위한 접근 방법에 대해 한 말씀 드리고자 합니다.

일단 꼭 기억하셔야 하는 거는 기계는 정직하다는 겁니다. 내가 시키지 않은 일은 하지 않습니다.
자신의 의도와 다른 이상한 결과가 나왔다고 생각할지 모르겠지만..
실제로는 기계에게 그렇게 움직이도록 이미 명령이 내려진 상태라는 거죠.

잘못된 결과가 출력되는 데에는 반드시 그렇게 되기 위한 조건이 있습니다.
화면에 나온 결과로부터 그 조건들을 하나씩 클리어 해가면, 결국 문제가 되는 조건을 발견할 수 있게 되는거죠.
디버깅이란게.. 결국은 논리적인 추론을 하나씩 검증해 내는 지루한 작업의 반복입니다.

전에 답글 달았던 건데, 아래 글을 예로 들어 보겠습니다.

http://kldp.org/node/137575

간단히 요약하면 파일에서 A 를 읽어, 메모리에 A 를 저장하고, A 를 화면에 출력하려고 했는데 B 가 출력되었다.. 가 되겠군요.
B 가 출력된 결과로 부터 왜 B 가 출력되게 되었는지, 단계적으로 발생할 수 있는 조건들을 나열해 봅니다.

B 가 출력되었다.
  +- 메모리에 B 가 저장되어 있다. (X)
  |  +- 메모리에 A 를 저장했는데, 출력 전에 이 값이 변했다.
  |     +- 메모리에 B 로 저장하는 부분이 있다.
  |     +- 메모리에 B 로 저장하는 부분이 없다. (buffer/stack overflow)
  |  +- 내가 메모리에 B 를 저장했다.
  |     +- 파일에서 읽은 값은 A 인데, B 로 변환하여 저장했다.
  |     +- 파일에 저장된 값이 B 였다.
  |        +- 다른 파일을 읽었다.
  +- 메모리에 A 가 저장되어 있는데, 내가 B 로 출력을 했다. (0)

트리 구조가 되는데, 거기서 발생 가능성이 높은 것부터 차례로 검증을 해서 소거해 나가면, 결국은 문제의 원인에 다다르게 됩니다.
다행히도 이 경우에는 첫번째 노드에서 바로 문제가 해결되었죠.

이 문제를 다른 사람에게 설명해서 해결하려고 한다면, 처음 요약한 것 같이 사실 관계를 명확히 할 수 있는 구체적인 서술/근거가 필요합니다.

- 하고자 하려는 일과 실행 환경
- 내가 구현한 (또는 시도한) 방법
- 화면에 표시된 결과 (또는 실행 결과)

위 세가지가 구체적으로, 코드/화면 첨부해서 제시되어야 합니다. (버그 레포트와 비슷)
자세한 건 아래 링크를 참조해 보세요.

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 참조

#ifdef DEBUG_PRINT
#define	DPRINT	printf
#else
#define	DPRINT	(void)0
#endif

별도로 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 』

lhs8421478의 이미지

아직 제가 스킬이 많이 부족해서 이러한 문제가 자꾸 생기는거 같네요 ㅠㅠ

문제점을 찾고 편법인거 같지만 처리를 했습니다..

msg라는 구조체 변수가 저장된 메모리 영역대가 아무리 봐도 시스템 메모리를 건드리는거 같아 힙메모리 역영대로

돌려 버렸습니다....

일단 처리는 했는데 또 무슨 문제가 생기게 될지 모르겠네요 ㅠㅠ

ymir의 이미지

아래 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 』

lhs8421478의 이미지

아직은 많이 미숙해서 ....

더욱 많은 연습과 공부가 필요할것 같아요 ....

bushi의 이미지

typedef struct _msg_buf {
        long search_code;
        char mtext[MAX_LENGTH];
}msg_buf_t;

msgrcv(..., msg, MAX_LENGTH, ..., ...); 

msgsnd(..., msg, MAX_LENGTH, ...);

lhs8421478의 이미지

아직 잘 몰라서 그러는데요...
msgq 구조체에서 인식하기 위해서 왜 long타입을 사용하는 것인가요?

int타입을 사용하면 안되는건가요??

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.