소켓 통신의 문제점.. 과연 무엇일까요..ㅠㅠ

wnldirqhrdyd의 이미지

안녕하세요

리눅스로 서버를 구현중입니다.
클라이언트는 윈도우기반 닷넷입니다.

접속하는 모든 클라이언트에게 브로드캐스팅 하는 구조이구요
클라이언트에게 3초마다 한번씩 데이터를 전송합니다.

문제는 서버가 종료될때인데요
서버가 정상종료가 아닌 강제종료
ex) kill -9 서버의프로세스ID
이렇게 죽여버리면 클라이언트가

null값인 데이터를 계속 받네요

과연 무엇이 문제 일까요

서버의 전송버퍼에 남아있는 데이터를 서버 프로세스가 죽은 후에도 계속 전송하는건가요
아님 이미 전송된 클라이언트의 수신버퍼의 내용을 클라이언트가 읽는걸까요

이상한점은 서버의 전송버퍼에 남아있는 데이터를 전송하는거라고 한다면
클라이언트가 null값이 아닌 정상적인 데이터를 받아야 하는게 아닌가요?
마찬가지로 클라이언트의 수신버퍼에 남아있는 데이터를 읽어오는것이라해도
정상적인 데이터의 값이 나와야 할것 같은데

왜 null값을 계속 받아오는 건지..
도통 이해가 되질 않습니다.

제발 조언 부탁드립니다
혹시나해서 소스 첨부해보겠습니다.

=================================================================

/*******************************************************************************
ClientManager.c
*******************************************************************************/

//========================헤더파일 로드.... & 상수값 설정 ===================================
#include "Common.h"
#include
#include
#include
#include
#include
#include
#include

#define BUFSIZE 1024
#define WRITE_BUF_SIZE 100
//=====================================================================================

//================================전역 변수 선언 ========================================
char Buf[BUFSIZE];
int serverSock;
struct timeval timeout;
//=====================================================================================

//===========================시그날 핸들러 처리 함수 ======================================
void signal_handler(int signo)
{
// do...... something...
RuntimeLog("*** Client Out -> Broken Pipe... ");
}
//=====================================================================================

//====================================메인 함수 =========================================
main()
{
//=========================변수선언========================
int clientSock, sockfd;
int client[FD_SETSIZE];
int i, clientCnt, msgLen;
int fd_num, maxfd;
char smsg[PACKET_SIZE];
fd_set readfds, allfds;
int iTest=0;
int rRst=0;
time_t time_now;
//=========================================================
//TEST 전문 내용.... ------------------------------
int wi = 0;
int nBufCnt = 0;
char writeBuf[WRITE_BUF_SIZE];
char testBuf[5000];
unsigned char jun[] =
"010000050060005000400030"
"0000000100005002"
"0000110002100040000007500500035001001010010100100000000000000010000000050000000300000003"
"00000001000100010000000020002000100000000200030001000000002000400010"
"000000000000000000000000020100224105601127-0-0-1 "
"000000000000000000000000020100224105601127-0-0-1 "
"00000001PROCESS명 00000012010022410560100:00:30030015201002241056010"
"000000010001V1 F1 201002241056010001"
"0000120003100010000007500500035001001010010000000000000000000020000000100000000500000002"
"00000003000100010"
"000000000000000000000000020100224105601127-0-0-1 "
"000000000000000000000000020100224105601127-0-0-1 "
"00000003PROCESS명 00000012010022410560100:00:30030015201002241056010";

memset(testBuf, 0x00, sizeof(testBuf));
sprintf(testBuf, "%c%010d%s%c", 0x02, strlen(jun), jun, 0x03); // 1 + 10 + 689 + 1 = 701
// ---------------------------------------------------

//=======================시그널 핸들러 함수 호출.. ===========================
// signal(SIGPIPE, signal_handler); //SIGNAL 신호 핸들러..
signal(SIGPIPE, SIG_IGN); //SIGNAL 신호 무시..
//=======================================================================

//=======================shared memory 설정, 서버소켓 설정 ================
SetShMemory(SHR_ADDR);
serverSock = ServerSocketBind(9797);

fd_num = 0;
clientCnt = -1;
clientSock = serverSock;
maxfd = serverSock;
//=======================================================================
for(i=0; i < FD_SETSIZE; i++)
client[i] = -1;

FD_ZERO(&readfds);
FD_SET(serverSock, &readfds);

while(1)
{
RuntimeLog("====================================================");

// 1. Read Sared Memory
ReadShMemory(Buf);
// RuntimeLog("Read Shared Memory : %s", Buf);

time(&time_now);
// RuntimeLog(ctime(&time_now));

// 2. Select
// 3. 접속된 클라이언트가 있으면 SH Memory 내용을 Write
++iTest;
allfds = readfds;

timeout.tv_sec = 0; // 아래에서 sleep 을 설정
timeout.tv_usec = 1;

//=========SELECT ============ select 함수 설정
RuntimeLog("1) select .............. ");
fd_num = select(maxfd+1, &allfds, (fd_set *)0, (fd_set *)0, &timeout);
// fd_num = select(maxfd+1, &allfds, (fd_set *)0, (fd_set *)0, NULL);

if(fd_num < 0)
{
RuntimeLog("*** [ERROR] select ");
continue;
}

// if(fd_num == 0) continue;
// RuntimeLog(" fd_num=%d", fd_num);

for(i=0; i < FD_SETSIZE; i++)
{
if ( client[i] > -1 ) RuntimeLog(" client[%d]=%d", i, client[i]);
}

//============================
if(FD_ISSET(serverSock, &allfds))
{
//================ACCEPT===============
clientSock = accept(serverSock, (struct sockaddr *)0, (int *)0);

for(i = 0; i < FD_SETSIZE; i++)
{
if(client[i] <0)
{
client[i] = clientSock;
RuntimeLog(">>>>>>>>>> clientSock saved position=[%d] : clientSocknum = [%d]\n", i, clientSock);
break;
}
}

if(i==FD_SETSIZE)
{
RuntimeLog("*** Warning : Full Socket ");
close(sockfd);
client[i] = -1;
}

FD_SET(clientSock, &readfds);

if(clientSock > maxfd) maxfd = clientSock;
if(i > clientCnt) clientCnt = i;
if(--fd_num <= 0) continue;
}

//=========================================== 접속된 클라이언트에게 브로드캐스팅
for(i=0; i<=clientCnt; i++)
{
if((sockfd = client[i]) < 0) continue;

RuntimeLog("2) write.........connected client count=%d", clientCnt+1);
RuntimeLog(" - client[%d]=%d", i, sockfd);
RuntimeLog(" - fd_num=%d", fd_num);

nBufCnt = (strlen(testBuf) / WRITE_BUF_SIZE) ;
//=========================================================

if( (strlen(testBuf) % WRITE_BUF_SIZE) != 0 ) ++nBufCnt;

RuntimeLog(" > nBufCnt=[%d]", nBufCnt);

for(wi=0; wi < nBufCnt; wi++)
{
memset(writeBuf, 0x00, WRITE_BUF_SIZE);
memcpy(writeBuf, testBuf+(WRITE_BUF_SIZE*wi), WRITE_BUF_SIZE );
RuntimeLog(" >%2d's [%s]", wi, writeBuf);

// WRITE...
write(sockfd, writeBuf, WRITE_BUF_SIZE);
}

//==========READ================= 종료된 클라이언트 검사
if(FD_ISSET(sockfd, &allfds))
{
memset(smsg, 0x00, PACKET_SIZE);

if(msgLen = read(sockfd, smsg, PACKET_SIZE)<=0)
{
close(sockfd);
FD_CLR(sockfd, &readfds);
client[i] = -1;
}
}
}
//===========================================
// 4. 3초 sleep
sleep(3);
}
}

==============================================================================

jos77의 이미지

올리신 것은 서버측 소스 같군요. SIGPIPE 까지 처리하셨으니 소켓이 문제가 되었을 것 같진 않네요
커널차원까지 가다보면 소켓이 닫힐 때 문제를 일으킬 확률이 0% 라고는 못하지만...
의심이 가는 것은 클라이언트 측 아닐까 궁금하네요 null 데이터를 계속 받는 다고 하셨는데
소켓 접속이 끊어졌다면 block 이 되던가 close 처리가 되어야 할텐데 0 이라는 데이터를 계속 받는 거라면...
소켓 버퍼에서 무조건 데이터를 읽도록 클라이언트 측 처리가 잘못되었을 가능성이 있습니다...

-----
안녕하세요 소프트웨어 공학센터 장원석 책임입니다.
http://www.software.kr

댓글 달기

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