서버소켓프로그램 - 왜 자꾸 죽을까요??????

maindb의 이미지

C 프로그래밍 초보 입니다.
간단한 서버 소켓프로그램을 제작했습니다.
쓰레드 인데...

아래 소스를 보시면 아시겠지만...
8088 포트로 접속하여 문자열을 날리면 buf 변수에 그 스트링을 담아서
system 함수로 외부 프로그램을 실행합니다. 아래에서는 ls -al 을
실행하도록 했습니다.

그런데 문제는 실행하고 일정시간 지나면 계속 죽는 것입니다.
데몬이 죽을 현장 목격을 해보니
'파이프가 깨졌습니다.' 와 같은 메세지가 나오면서 죽습니다.
이유가 뭘까요?

한번 보시고 의견 부탁드립니다.

#include "ServerSocket.h"
#include "SocketException.h"

#include <pthread.h>
#include <sys/poll.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <string>
#include <iostream>

using namespace std;

#define MAX_SOCKET	1000
#define FIFO_NAME	"fifo"
#define BUF_SIZE	512

int pollcount;

void* ThreadFIFO(void* arg) {
   int fd, *i = (int *)arg;
   char buf[BUF_SIZE];
   fd = open(FIFO_NAME, O_WRONLY);
   printf("Thread started\n");
   while (true) {
      sprintf(buf, "%dth job is doing(thread).\n", *i);
      write(fd, buf, BUF_SIZE);
      sleep(0);
   }
}

int main ( int argc, int argv[] )
{
	std::cout << "running....\n";
	char buffer[255];

	try
	{
		// Create the socket
		ServerSocket server ( 8088 );

//		while ( true )
		{
			int sp = 0;
			int num = 0, i;
			char buf[BUF_SIZE];
			pthread_t pt;
			struct pollfd pFd[MAX_SOCKET];

			mkfifo(FIFO_NAME, 0777);
			
			pthread_create(&pt, NULL, ThreadFIFO, (void *)&num);

			pFd[2].fd = -1;
			pFd[1].fd = open(FIFO_NAME, O_RDONLY);
			pFd[1].events = POLLIN;


			pFd[0].fd = server.hSocket();
			pFd[0].events = POLLIN;

			ServerSocket new_sock[MAX_SOCKET];
			pollcount = 2;

			try
			{
				while ( true )
				{
					sleep(0);
					num = poll(pFd, MAX_SOCKET, -1);
					for (i = 0; i < MAX_SOCKET; i++) 
					{
						if (pFd[i].revents & (POLLIN | POLLERR)) 
						{
							int temp = new_sock[sp].hSocket();
							if (i == 0)
							{
								if( sp > MAX_SOCKET ) sp = 0;

								if( temp != -1 )close( new_sock[sp].hSocket() );
								server.accept ( new_sock[sp] );
								if( pollcount > MAX_SOCKET ) pollcount = 2;
								pFd[pollcount].fd = new_sock[sp++].hSocket();
								pFd[pollcount++].events = POLLIN;
//								printf("Client connected\n");
							} 
							else if( i == 1 )
							{
								memset( buf, 0, BUF_SIZE );
								if (read(pFd[i].fd, buf, BUF_SIZE) <= 0) 
								{
									printf("FIFO Error. Please restart socket server.\n");
									close(pFd[i].fd);
									pFd[i].fd = -1;
									exit(-1);
								} 
//								else printf("%s", buf);
							}
							else // i == 2
							{
								memset( buf, 0, BUF_SIZE );
								if (read(pFd[i].fd, buf, BUF_SIZE) <= 0) 
								{
									printf("Socket closed\n");
									close(pFd[i].fd);
									pFd[i].fd = -1;
								} 
								else
								{
									printf("Ok Process\n");
									sprintf(buffer, "ls -al %s", buf);
									system(buffer);
								}
							}
						}
					}
				}
			}
			catch ( SocketException& ) {}

		}
	}
	catch ( SocketException& e )
	{
	std::cout << "Exception was caught:" << e.description() << "\nExiting.\n";
	}

  return 0;
}
익명 사용자의 이미지

SIGPIPE를 무시하도록 해주면 안죽습니다.

maindb의 이미지

ㅠ.ㅠ

SIGPIPE를 무시하도록 해주면 안죽는다는게
무슨 말인지 잘 모르겠습니다.
지금 열심히 공부는 하고 있는데....
어떻게 고치면 좋을지 조금만 더 조언을 해주세요.

죄송합니다.

xiphoid의 이미지

간단하게는 signal(SIGPIPE,SIG_IGN)를 해주시면되고여
자세한거는 시그널부분을 공부하시죠

아 피곤해

maindb의 이미지

창피하지만....

무시해버리고 싶다면...
signal(SIGPIPE, SIG_IGN)
을 위 소스에서는 어디에 삽입하면 적당할까요?
그리고 그렇게 그냥 무시해도 될까요?

계속 공부는 하고 있는데...
다른사람것 같다 쓰려는 초보의 한계이군요.
죄송합니다 ㅠ.ㅠ

mach의 이미지

프로그램 시작시 한번 불러주면됩니다.

Quote:
"나는 절대로 죽을 수 없다. 클라이언트를 죽여서/거부해서 내가 산다면, 클라이언트는 무수히 죽일 수 있다."
- 서버 어록중에서-

* 시그널을 무시해도 좋은가?
당연히, 좋을리 없지요.
그러나, 서버 어록처럼 죽는것 보다는 낫다. 또한, 서버프로그래머는 서버어록을 준수하도록 서버를 만들어야 합니다.
무시하지 않으려면? 해당 시그널에 핸들러를 달아줘야합니다.

*또다른 의문?
SIGPIPE말고 시그널은 참 많은데, .....??????

* 또다른 의문까지 문제를 푸시면 다 푼것입니다. 유닉스/리눅스에서 시그널처리는 한국인 밥상의 김치와 같습니다.
시그널에 대해서 한번 깊게 고찰의 시간을 가져보세요. 두루 사용되는것이니.

------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.

최종호의 이미지

음... 딴 얘기지만

코드를 살짝 봤는데, C++ 에서 요즘 try / catch 많이 쓰나요?

sleep(0) 은 어디에 쓰는걸까요?

pthread_yield() / yield() / sched_yield() 같은 것일까요?

서버 어록은 어디에 있는건가요? 구글에 안나오던데...

bw001730의 이미지

SIGPIPE는 유효하지 않은 디스크립터에
write 함수를 호출할때 발생합니다.

저도 그거 모르고 삽질하다가
한동안 삽질을 엄청했던 기억이...

maindb의 이미지

답변 주신분들 감사합니다.
덕분에 감을 좀 잡았네요 ^^

ulra의 이미지

저두 write 시 sigpipe가 나와서 여기 답변처럼

signal(SIGPIPE, SIG_IGN);

을 추가했습니다.
그런데 변한게 없고 똑같이 sigpipe가 나옵니다.
다른 방법은 없을까요?
그리고 제가 가지고 있는 소스는 sigchld에 대해sigaction을 사용하고 있습니다.
그런데 이거 사용법이 복잡해서 못사용하고 있습니다. sigaction명령을 위의 signal명령과 같은 효과를 낼려면 어떻게 코딩을 해야하나요?

OTL 즐!!!! (좌절 금지!!!)

alone의 이미지

 void Signal_Init(void)
 {
     struct sigaction act_print_exit;
     struct sigaction act_print_ignore;
     struct sigaction act_print_init;
     struct sigaction act_print_permit;

     memset(&act_print_exit, 0x00, sizeof(struct sigaction));
     memset(&act_print_ignore, 0x00, sizeof(struct sigaction));
     memset(&act_print_init, 0x00, sizeof(struct sigaction));
     memset(&act_print_permit, 0x00, sizeof(struct sigaction));

     act_print_exit.sa_handler = Signal_Print_Exit;
     act_print_ignore.sa_handler = Signal_Print_Ignore;
     act_print_init.sa_handler = Signal_Print_Init;
     act_print_permit.sa_handler = Signal_Print_Permit;

     sigemptyset(&(act_print_exit.sa_mask));
     sigemptyset(&(act_print_ignore.sa_mask));
     sigemptyset(&(act_print_init.sa_mask));
     sigemptyset(&(act_print_permit.sa_mask));

     act_print_exit.sa_flags = 0;
     act_print_ignore.sa_flags = 0;
     act_print_init.sa_flags = 0;
     act_print_permit.sa_flags = 0;

 //  sigfillset(&(act_print_exit.sa_mask));
 //  sigfillset(&(act_print_ignore.sa_mask));
 //  sigfillset(&(act_print_init.sa_mask));
 //  sigfillset(&(act_print_permit.sa_mask));

     sigaction(SIGSEGV, &act_print_exit, NULL);
     sigaction(SIGABRT, &act_print_exit, NULL);
     sigaction(SIGILL, &act_print_exit, NULL);
     sigaction(SIGTRAP, &act_print_exit, NULL);
     sigaction(SIGSYS, &act_print_exit, NULL);
     sigaction(SIGXCPU, &act_print_exit, NULL);
     sigaction(SIGXFSZ, &act_print_exit, NULL);
     sigaction(SIGFPE, &act_print_exit, NULL);
     sigaction(SIGINT, &act_print_exit, NULL); //Ctrl-C

     sigaction(SIGUSR1, &act_print_ignore, NULL);
     sigaction(SIGCHLD, &act_print_ignore, NULL);
     sigaction(SIGTERM, &act_print_ignore, NULL); //기본적인 15번
     sigaction(SIGQUIT, &act_print_ignore, NULL);
     sigaction(SIGPIPE, &act_print_ignore, NULL);

    //signal 1은 init신호
    sigaction(SIGHUP, &act_print_init, NULL);

    //usr2는 접속 금지
    sigaction(SIGUSR2, &act_print_permit, NULL);
}

void Signal_Print_Exit(int s)
{
    LOGOUTWAR("Signal Exit : %s(%d)", Get_Signal_Name(s), s);
    Exit();
}

void Signal_Print_Ignore(int s)
{
    LOGOUTWAR("Signal Ignore : %s(%d)", Get_Signal_Name(s), s);
}

void Signal_Print_Init(int s)
{
    LOGOUTWAR("Signal Initialize..... : %s(%d)", Get_Signal_Name(s), s);
}

void Signal_Print_Permit(int s)
{
    if(g_bConnectionPermit) g_bConnectionPermit = false;
    else g_bConnectionPermit = true;
    LOGOUTWAR("Signal Permit(%d) Change..... : %s(%d)", g_bConnectionPermit, Get_Signal_Name(s), s);
}

전 대충 이렇게 사용합니다..
처음 시작할시에.. Signal_Init() 한번 호출 하심이..

내일은 내일일뿐.....

ulra의 이미지

위에 분이 주신 소스를 참고로 해서 수정했는데 잘 됩니다.

감사합니다.

그런데 질문이 있습니다.
일반적으로 그냥 실행하면 sigpipe 핸들러를 실행합니다.
그런데 gdb로 디버깅 모드로 띄우면 sigpipe 핸들러를 실행하지
않고 gdb가 sigpipe 시그널이 나왔다고 표시하고
프로그램을 정지시키네요.

혹시 제가 잘못한 것이 있어서 이런 현상이 생긴건가요? 아님
원래 그런건가요?

참고로 gdb는 래드햇 리눅스 7.2에 있는 것입니다.

OTL 즐!!!! (좌절 금지!!!)

amister의 이미지

gdb가 디버깅중인 프로그램보다 앞서서 캐치하는 시그널들이 있습니다. SIGPIPE도 마찬가지입니다.

만약 계속 디버깅을 진행하고 싶으시면 cont 명령을 주면 됩니다.
매번 이렇게 하는 것이 귀찮으시면 .gdbinit 에 다음과 같은 옵션을 추가해주세요.

handle SIGPIPE nostop

ulra의 이미지

답변주신 모든 분들께 감사를 드립니다.

오늘 하루 좋은 하루 되세요.

OTL 즐!!!! (좌절 금지!!!)

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.