pthread를 사용 server만드는데 오류가 계속 뜹니다.

kash0921의 이미지

쓰레드를 사용해서 파일 보내주는 서버 프로그램 만드는데 자꾸 segmentation fault 가 생기는데 어떻게 해야 문제가 해결이 되는지 모르겠습니다.

pthread_create를 부를때 문제가 있는거 같은데 어찌 해야 하는지 잘 모르겠내요.
알려주시면 감사하겠습니다. 아직 완성한 프로그램은 아니지만 혹시 그 외에 문제점이라도 있으면 알려주시면 감사하겠습니다. 이 프로그램 컴파일후 실행시키면 잘 돌아가는 듯 하나 client 에서 파일 요청을 하면 segmentation fault가 뜹니다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <pthread.h>

#define MYPORT 6001
#define FILENAME_LEN 256
#define BUFFER_LEN (1024 * 1024)
#define BACKLOG 10
/* #define THREAD_NUM */

void *serving_request(void *fd)
{
  int new_fd, num_bytes, file_size;
  int byte_read, byte_written, file_requested, retval;
  char file_name[FILENAME_LEN];
  char buf[BUFFER_LEN];

  struct stat file_stat;

  memset(file_name,'\0', FILENAME_LEN);

  new_fd = *((int *) fd);

  pthread_detach(pthread_self());
    
  num_bytes = recv(new_fd, file_name, FILENAME_LEN, 0);

  if(num_bytes == 0) {
    close(new_fd);
    break;
  } else if(num_bytes < 0) {
    perror("recv");
    close(new_fd);      
    break;
  }

  file_name[num_bytes] = '\0';
  /* open a file that include path */
  file_requested = open(file_name, O_RDONLY);

  /* open function error checking */
  if(file_requested == -1) {
    file_size = htonl(-1);
    write(new_fd, &file_size, sizeof(file_size));
    close(new_fd);
    return (NULL);
  }

  fstat(file_requested, &file_stat);
  file_size = 0;

  file_size = htonl(file_stat.st_size);

  if(write(new_fd, &file_size, sizeof(file_size)) == -1) {
    perror("write");
    break;
  }
  
  byte_read = 0;
  byte_written = 0;

  while(byte_read < file_stat.st_size) {
    memset(buf, '\0', BUFFER_LEN);
    
    retval = read(file_requested, buf, BUFFER_LEN);
    if(retval == -1) {
      perror("read");
      break;
    }
    
    byte_read += retval;
    
    retval = send(new_fd, &buf, byte_read - byte_written, 0);
    if(retval == -1) {
      perror("send");
      break;
    }
    byte_written += retval;
  }
  printf("File size %d\n",ntohl(file_size));
  printf("Sent all\n");
  close(file_requested);
  close(new_fd);
  return (NULL);
}

int main()
{
  int sockfd, *new_fd;
  int sin_size, thread_id; 
  /*  pthread_t p_thread[THREAD_NUM]; */
  pthread_t threads;

  struct sockaddr_in server_addr;
  struct sockaddr_in client_addr;

  /* creating sock descriptor */
  if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("socket");
    exit(1);
  }

  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(MYPORT);
  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  memset(&(server_addr.sin_zero), '\0', 8);

  if(bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1){
    perror("bind");
    exit(1);
  }

  if(listen(sockfd, BACKLOG) == -1) {
    perror("listen");
    exit(1);
  }
  printf("Socket listening..\n");

  sin_size = sizeof(struct sockaddr_in);
  
  while(1) {
    new_fd = malloc(sizeof(int));
    if((*new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size)) == -1) {
      perror("accept");
      exit(1);
    }
    printf("Server: Got connection from %s\n", inet_ntoa(client_addr.sin_addr));
    
    thread_id = pthread_create(
			       &threads, 
			       NULL, 
			       &serving_request, 
			       new_fd);
    if(thread_id < 0) {
      perror("pthread_create");
      exit(1);
    }

    /* pthread_detach(threads); */
  }
  
  close(sockfd);
  return 0;
}
pynoos의 이미지

retval = send(new_fd, &buf, byte_read - byte_written, 0);

buf에 대한 포인터를 넘기는 것이 아니라 buf를 넘겨야 할 것 같습니다.
그리고, 쓰레드에 넘기는 void * 인자는 malloc만 있고 free는 없군요.
쓰레드를 실행하는데 처음 만나는 if 안의 break는 괴상하게 보입니다.
new_fd에 대한 write, send 가 동시에 나오는 것보다는 하나로 통일하는 것이 좋겠습니다.
처음 stat하는 순간의 크기가 도중에 줄어 들거나 늘지 않는다는 보장이 없으므로 파일을 읽는데 -1 만 확인하지 마시고, 0 도 확인하는 것이 좋습니다.

익명 사용자의 이미지

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <unistd.h>
#include <getopt.h>
#include <netdb.h>
#include <pthread.h>

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

#define DICE_PORT 6173

int do_debug = 0;
int do_thread = 0;
int do_stdin = 0;
int do_sleep = 0;

struct sockets {
int local;
FILE *in, *out;
};

struct sockets *get_sockets(int);
int socket_setup(void);
int debug(char *, ...);
int fail(char *, ...);
int warn(char *, ...);
int roll_die(int);
void *roll_dice(void *);

int
debug(char *fmt, ...) {
va_list ap;
int r;

va_start(ap, fmt);
if (do_debug) {
r = vfprintf(stderr, fmt, ap);
} else {
r = 0;
}
va_end(ap);
return r;
}

int
warn(char *fmt, ...) {
int r;
va_list ap;
va_start(ap, fmt);
r = vfprintf(stderr, fmt, ap);
va_end(ap);
return r;
}
int
fail(char *fmt, ...) {
int r;
va_list ap;
va_start(ap, fmt);
r = vfprintf(stderr, fmt, ap);
exit(1);
/* notreached */
va_end(ap);
return r;
}

int
roll_die(int n) {
return rand() % n + 1;
}

/* read dice on standard input, write results on standard output */
void *
roll_dice(void *v) {
struct sockets *s = v;
char inbuf[512];

/* think globally, program defensively */
if (!s || !s->out || !s->in)
return NULL;
fprintf(s->out, "enter die rolls, or q to quit\n");
while (fgets(inbuf, sizeof(inbuf), s->in) != 0) {
int dice;
int size;
if (inbuf[0] == 'q') {
fprintf(s->out, "buh-bye!\n");
if (s->local == 0) {
shutdown(fileno(s->out), SHUT_RDWR);
}
fclose(s->out);
fclose(s->in);
if (s->local == 0) {
free(s);
}
return 0;
}
if (sscanf(inbuf, "%dd%d", &dice, &size) != 2) {
fprintf(s->out, "Sorry, but I couldn't understand that.\n");
} else {
int i;
int total = 0;
for (i = 0; i < dice; ++i) {
int x = roll_die(size);
total += x;
fprintf(s->out, "%d ", x);
fflush(s->out);
if (do_sleep)
sleep(1);
}
fprintf(s->out, "= %d\n", total);
}
}
return 0;
}

int
main(int argc, char *argv[]) {
int o;
int sock;
while ((o = getopt(argc, argv, "dstS")) != -1) {
switch (o) {
case 'S':
do_sleep = 1;
break;
case 'd':
do_debug = 1;
break;
case 's':
do_stdin = 1;
break;
case 't':
do_thread = 1;
break;
}
}

if (do_stdin) {
struct sockets s;
s.local = 1;
s.in = stdin;
s.out = stdout;
if (do_thread) {
pthread_t p;
pthread_create(&p, NULL, roll_dice, (void *) &s);
} else {
roll_dice(&s);
exit(0);
}
}

sock = socket_setup();
while (1) {
struct sockets *s = get_sockets(sock);
if (s) {
if (do_thread) {
pthread_t p;
pthread_create(&p, NULL, roll_dice, (void *) s);
} else {
roll_dice(s);
exit(0);
}
}
}
return 0;
}

int
socket_setup(void) {
struct protoent *tcp_proto;
struct sockaddr_in local;
int r, s, one;

tcp_proto = getprotobyname("tcp");
if (!tcp_proto) {
fail("Can't find TCP/IP protocol: %s\n", strerror(errno));
}
s = socket(PF_INET, SOCK_STREAM, tcp_proto->p_proto);
if (s == -1) {
fail("socket: %s\n", strerror(errno));
}
one = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
memset(&local, 0, sizeof(struct sockaddr_in));
local.sin_family = AF_INET;
local.sin_port = htons(DICE_PORT);
r = bind(s, (struct sockaddr *) &local, sizeof(struct sockaddr_in));
if (r == -1) {
fail("bind: %s\n", strerror(errno));
}
r = listen(s, 5);
if (r == -1) {
fail("listen: %s\n", strerror(errno));
}
return s;
}

struct sockets *
get_sockets(int sock) {
int conn;
if ((conn = accept(sock, NULL, NULL)) < 0) {
warn("accept: %s\n", strerror(errno));
return 0;
} else {
struct sockets *s;
s = malloc(sizeof(struct sockets));
if (s == NULL) {
warn("malloc failed.\n");
return 0;
}
s->local = 0;
s->in = fdopen(conn, "r");
s->out = fdopen(conn, "w");
setlinebuf(s->in);
setlinebuf(s->out);
return s;
}
}

참조 : http://www-903.ibm.com/developerworks/kr/linux/library/l-pthred.html

댓글 달기

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