[질문] 코드 에러좀 봐주세요. T_T

익명 사용자의 이미지

이거는 소켓서버에서 Select를 사용해서, 다중 Access를 지원하는 서버측
코드거든요.
근데, 1차적으로 클라이언트에서 데이타를 가져와서 쓰기까지는 성공하는
데, 그 이후에는 "Segmentation fault"란 에러가 나거든요.
어떤 부분이 이상한지 감이 잘 안와서요. 이거 다른 책 소스를 참조한건
데..
잘아시는 고수님들의 도움을 필요로 합니다. 흑흑...

#include
#include
#include
#include
#include

#define PORT 9090
#define MAXCLIENT 100
#define BUFSIZE 1024+1
#define SUCCESS 1
#define FAIL 0

typedef struct {
char buffer[BUFSIZE];
int clientFD ;
FILE *tmpFile ;
} CLIENTINFO ;

CLIENTINFO client[MAXCLIENT] ;

static void errorMsg(const char *on_what) {

fputs(on_what,stderr) ; /* on_what을 stderr로 입력 */
fputc('\n',stderr) ;
exit(1) ;
}
int setup(char *servAddr, int backlog) {


int returnVal ;
char *serv_addr = NULL ;
char *serv_port = NULL ;
struct sockaddr_in addr_serv,addr_clnt ;
int len_inet ;
int sockfd, maxfd, connfd, maxindex, nready ;
int i ;
char *name ;
ssize_t n,n2 ;
int writeCnt ;


fd_set rset, allset ;


/*server address */
serv_addr = servAddr ;

/* Create a server socket to use */
sockfd = socket(PF_INET,SOCK_STREAM,0) ;
if(sockfd == -1)
errorMsg("socket(2)") ;

/* Create a Server Socket address */
bzero(&addr_serv,sizeof(addr_serv)) ;
addr_serv.sin_family = AF_INET ;
addr_serv.sin_port = htons((unsigned short)(PORT)) ;

if(strcmp(serv_addr, "*") != 0) {
addr_serv.sin_addr.s_addr = inet_addr
(serv_addr) ;
if(addr_serv.sin_addr.s_addr == INADDR_NONE)
errorMsg("bad address") ;
}
else {
/* Wild address */
addr_serv.sin_addr.s_addr = INADDR_ANY ;
}


/* Bind the server address */
len_inet = sizeof addr_serv ;
returnVal = bind(sockfd,(struct sockaddr_in *)&addr_serv,
len_inet) ;
if(returnVal == -1)
errorMsg("bind(2)") ;

/* Make it a Listening socket */
returnVal = listen(sockfd,backlog) ;

if(returnVal == -1) {
errorMsg("Cannot listen.\n") ;
return -1 ;
}

maxfd = sockfd ;
maxindex = -1 ;
for(i=0;i client[i].clientFD = -1 ;
FD_ZERO(&allset) ;
FD_SET(sockfd, &allset) ;

for( ; ; ) {
rset = allset ;
nready = select(maxfd +1, &rset, NULL,NULL,NULL) ;
if(FD_ISSET(sockfd,&rset)) {
len_inet = sizeof addr_clnt ;
connfd = accept(sockfd,(struct sockaddr
*)&addr_clnt, &len_inet) ;
for(i=0;i if(client[i].clientFD<0) {
client[i].clientFD =
connfd ;
break ;
}
if(i == MAXCLIENT)
errorMsg("Too Many Clients ") ;
FD_SET(connfd, &allset) ;
if(connfd>maxfd)
maxfd = connfd ; /* for Select
*/
if(i>maxindex)
maxindex = i ; /* max index in
clients for data */
if(--nready <= 0)
continue ; /* no more readable
descriptors */
}
for(i=0;i<=maxindex;i++) { /* check all clients
for dat\a */
if((sockfd = client[i].clientFD) <0)
continue ;
if(FD_ISSET(sockfd,&rset)) {

if((n=recv(sockfd, client
[i].buffer,BUFSIZE,0)) < 0) {
/* connection closed
by client */
close(sockfd) ;
FD_CLR
(sockfd,&allset) ;
client[i].clientFD = -
1 ;
}
else {


printf("Buffer content
result %s\n \n", client[i].buffer) ;

printf("%d Byte
received\n", n);
n2 = send(sockfd,client
[i].buffer, n, 0);
if(!(n==n2))
errorMsg
("Error occurred") ;
close(sockfd) ; /* 요
거 맞을까? 첵업해보기 */


}
if(--nready <= 0) {
printf("nready %
d\n", nready) ;
break ; /*no more
readable descriptiors */
}
}
}
}
return 1 ;

}

int main(int argc, char **argv) {

printf("=== Test MOL Server === \n") ;
if(!(setup("2XX.XXX.XXX", 10) == 1))
errorMsg("Server Failed\n") ;
getchar() ;
printf("Good Bye !") ;
exit(1) ;

return SUCCESS ;
}

익명 사용자의 이미지

제니 wrote..
이거는 소켓서버에서 Select를 사용해서, 다중 Access를 지원하는 서버 측
코드거든요.
근데, 1차적으로 클라이언트에서 데이타를 가져와서 쓰기까지는 성공하 는
데, 그 이후에는 "Segmentation fault"란 에러가 나거든요.
어떤 부분이 이상한지 감이 잘 안와서요. 이거 다른 책 소스를 참조한건
데..
잘아시는 고수님들의 도움을 필요로 합니다. 흑흑...



#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>


#define PORT 9090
#define MAXCLIENT 100
#define BUFSIZE 1024+1
#define SUCCESS 1
#define FAIL 0

typedef struct {
char buffer[BUFSIZE];
int clientFD ;
FILE *tmpFile ;
} CLIENTINFO ;


CLIENTINFO client[MAXCLIENT] ;

static void errorMsg(const char *on_what) {

fputs(on_what,stderr) ; /* on_what을 stderr로 입력 */
fputc('\n',stderr) ;
exit(1) ;
}
int setup(char *servAddr, int backlog) {


int returnVal ;
char *serv_addr = NULL ;
char *serv_port = NULL ;
struct sockaddr_in addr_serv,addr_clnt ;
int len_inet ;
int sockfd, maxfd, connfd, maxindex, nready ;
int i ;
char *name ;
ssize_t n,n2 ;
int writeCnt ;


fd_set rset, allset ;


/*server address */
serv_addr = servAddr ;

/* Create a server socket to use */
sockfd = socket(PF_INET,SOCK_STREAM,0) ;
if(sockfd == -1)
errorMsg("socket(2)") ;

/* Create a Server Socket address */
bzero(&addr_serv,sizeof(addr_serv)) ;
addr_serv.sin_family = AF_INET ;
addr_serv.sin_port = htons((unsigned short)(PORT)) ;

if(strcmp(serv_addr, "*") != 0) {
addr_serv.sin_addr.s_addr = inet_addr
(serv_addr) ;
if(addr_serv.sin_addr.s_addr == INADDR_NONE)
errorMsg("bad address") ;
}
else {
/* Wild address */
addr_serv.sin_addr.s_addr = INADDR_ANY ;
}


/* Bind the server address */
len_inet = sizeof addr_serv ;
returnVal = bind(sockfd,(struct sockaddr_in *) &addr_serv,
len_inet) ;
if(returnVal == -1)
errorMsg("bind(2)") ;

/* Make it a Listening socket */
returnVal = listen(sockfd,backlog) ;

if(returnVal == -1) {
errorMsg("Cannot listen.\n") ;
return -1 ;
}

maxfd = sockfd ;
maxindex = -1 ;
for(i=0;i<MAXCLIENT;i++)
client[i].clientFD = -1 ;
FD_ZERO(&allset) ;
FD_SET(sockfd, &allset) ;

for( ; ; ) {
rset = allset ;
nready = select(maxfd +1, &rset, NULL,NULL,NULL) ;
if(FD_ISSET(sockfd,&rset)) {
len_inet = sizeof addr_clnt ;
connfd = accept(sockfd,(struct sockaddr
*)&addr_clnt, &len_inet) ;
for(i=0;i<MAXCLIENT;i++)
if(client[i].clientFD<0) {
client[i].clientFD =
connfd ;
break ;
}
if(i == MAXCLIENT)
errorMsg("Too Many Clients ") ;
FD_SET(connfd, &allset) ;
if(connfd>maxfd)
maxfd = connfd ; /* for Select
*/
if(i>maxindex)
maxindex = i ; /* max index in
clients for data */
if(--nready <= 0)
continue ; /* no more readable
descriptors */
}
for(i=0;i<=maxindex;i++) { /* check all clients
for dat\a */
if((sockfd = client[i].clientFD) <0)

위의 부분에서 sockfd는 위에서 전체에 대한 fd값인데 왜 여기서
하나의 클라이언트의 소켓에 지정하셨나여???

궁금합니다...

별도의 변수( clientfd )로 받아서 아래에서 닫으시져...

위에 설명한 대로 해 보시져...

continue ;
if(FD_ISSET(sockfd,&rset)) {

if((n=recv(sockfd, client
[i].buffer,BUFSIZE,0)) < 0) {
/* connection closed
by client */
close(sockfd) ;

그리고 이것에 그것을 닫아버리네여...???

전체 소켓은 이미 뭉개졌고, 클라이언트 하나에 대한
소켓 마져도 닫으시군여...

그럼.. 머가 남지여???

FD_CLR
(sockfd,&allset) ;
client[i].clientFD = -
1 ;
}
else {


printf("Buffer content
result %s\n \n", client[i].buffer) ;

printf("%d Byte
received\n", n);
n2 = send(sockfd,client
[i].buffer, n, 0);
if(!(n==n2))
errorMsg
("Error occurred") ;
close(sockfd) ; /* 요
거 맞을까? 첵업해보기 */


}
if(--nready <= 0) {
printf("nready %
d\n", nready) ;
break ; /*no more
readable descriptiors */
}
}
}
}
return 1 ;

}

int main(int argc, char **argv) {

printf("=== Test MOL Server === \n") ;
if(!(setup("2XX.XXX.XXX", 10) == 1))
errorMsg("Server Failed\n") ;
getchar() ;
printf("Good Bye !") ;
exit(1) ;

return SUCCESS ;
}

익명 사용자의 이미지

몇 가지 문제점이 있군요.

1. bind() 함수 argument가 틀렸습니다. (struct sockaddr_in *) 이 아니라 (struct sockaddr *)로 캐스팅해야 하죠?
2. 어떤 클라이언트에서 입력이 들어왔는지를 확인하는 /* check all clients for data */ 루프에서 sockfd 변수를 사용한 것.
sockfd는 클라이언트로부터의 connect()를 listen()하는 소켓인데, clientFD 값을 할당하면 더이상 새로운 연결을
받아들일 수 없겠죠.
그냥 clientFD값을 사용하거나 다른 변수를 사용해야 합니다.

3. /* 요거 맞을까? 첵업해보기 */ 부분에서 소켓을 닫은 것. 뭐 문제라고 까지 할수는 없지만 한번 입력을 받은 후
서버가 접속을 끊어버리니까 애초의 의도와는 다른 것 같습니다.

4. if((n=recv(sockfd1, client[i].buffer,BUFSIZE,0)) < 0) 구문에서 '<'이 아니라 '<=' 이 필요합니다.
왜냐하면 클라이언트가 접속을 끊으면 n 값이 0이 되니까, 이럴 때도 처리해 줘야 하죠.

5. setup()의 무한 루프를 벗어날 수 없는 것 같은데, 이러면 main()에서 setup()이 리턴하는 일이 없을 것 같습니다.
그리고 만일 리턴한다 하더라고 exit(1)에서 프로세스가 종료되니까 reture SUCESS까지 제어가 도달할 것 같지 않군요.

몇 군데 손보고 나서 제대로 돌아가서 답변을 썼는데 혹시 빠뜨린 부분이 있는지 모르겠네요. 해보고 안되면 말씀해 주세요.

댓글 달기

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