소켓프로그래밍에서 문자열 주고 받는 질문입니다

ch0nn0m의 이미지

소켓프로그래밍 공부중에 궁금한게 3가지 정도 있습니다..
시작 한지 얼마 안된지라...쉽게 설명 부탁드릴께요..^^;

클라이언트 부분에서 서버로 보내는 문자열입니다

while(1)
{
         printf("ID : ");
         fgets(id,20,stdin);
         id[(strlen(id)-1)]='\0';
         write(sock,id,strlen(id));
 
         printf("PASSWORD : ");
         fgets(passwd,20,stdin);
         passwd[(strlen(passwd)-1)]='\0';
 
         write(sock,passwd,strlen(passwd));
}

서버에서 클라이언트 문자열을 받는것입니다(첫번째)

while((str_len=read(clnt_sock, id, sizeof(id))) > 0)
{
         id[str_len]='\0';
}
while((size=read(clnt_sock,passwd,sizeof(passwd)))>0)
{
         passwd[size]='\0';
}
         printf("%s\n",id);
         printf("%s\n",passwd);

서버에서 클라이언트 문자열을 받는것입니다(두번째)

while(1)
{
         str_len=read(clnt_sock, id, sizeof(id));
         if(str_len<0)
                  break;
         size=read(clnt_sock,passwd,sizeof(passwd));
         if(size<0)
                  break;
         id[str_len]='\0';
         passwd[size]='\0';
 
         printf("%s\n",id);
         printf("%s\n",passwd);
}

1) 첫번째것으로 했을경우는 printf문 값이 안나오네요..왜그런지...?

2) read()는 제가 할당할 버퍼만큼 한번에 다 못받아 올수 있다고 들은것 같은데...자기가 알아서 어쨌든 받아오는건지..? 따로 설정같은건 필요없는건가요??

3) 두번째것은 잘나오는데...클라이언트 부분에서 ctrl+c를 누를경우...서버는 무한루프를 도는것 같더라구요

chadr의 이미지

1.
fgets(id,20,stdin);
id[(strlen(id)-1)]='\0';

이중에서 두번째 줄은 의미가 없습니다. strlen함수가 NULL이 있는 곳까지 루프 돌면서
개수를 세는건데 NULL이 없는 상태에서 strlen으로 개수를 세고 그자리에 NULL을 넣는건 의미가 없습니다. id라는 배열을
fgets하기 전에 0으로 초기화 해주세요.

2.
자기가 알아서 어쨌든 다 받아오는건 없습니다. read함수의 리턴값을 이용하여 직접 다 받으셔야합니다.
이 코드로는 정상적으로 데이터를 다 읽어올 수 없습니다.

3.
이곳도 2와 마찬가지입니다. 받는 부분을 고치셔야합니다. 그리고..
str_len<=0 size<=0 으로 고쳐보세요..
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

freestyle의 이미지

fgets는 최대 두 번째 전달된 '버퍼의 크기 - 1' 만큼 읽을 수 있습니다.
그보다 적은 내용일 경우엔 크기만큼 읽고,
c 문자열 표현방식을 충족시키기 위해 두 경우 모두 '\0'로 마무리 합니다.

따라서 strlen을 사용하는 것은 적절합니다(입력 데이터의 특성에 따라 모든 상황에서 완벽하진 않지만).
--------------------------
Go to the U-City

----------------------------------------------------------------------------------------
Don't Feed the Trolls!
----------------------------------------------------------------------------------------

chadr의 이미지

다시 찾아보니 freestyle님이 말씀하신 동작방식이 맞습니다. :)

그렇다면 fgets가 NULL로 마무리 해주는데 다시 코드에서 NULL로 마무리 해주는건
불필요한게 맞겠습니다.
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

freestyle의 이미지

다시 말씀드립니다만 '\0'은 NULL이 아닙니다.

[참고] http://kldp.org/node/28150
[참고] http://kldp.org/node/240
---------------------
Go to the U-City

----------------------------------------------------------------------------------------
Don't Feed the Trolls!
----------------------------------------------------------------------------------------

chadr의 이미지

둘이 동일한건 아니지만 윈도우나 리눅스나 \0이나 NULL을 사용해도 의미가 달라지는건 아니므로 그냥 사용했습니다.

굳이 강조를 하지 않으셔도 알고 있습니다. :)
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

neogeo의 이미지


위에 코드 내용을 안봐서 모르겠지만 id 안에 '\0' 이 들어있지 않다면

id[(strlen(id)-1)]='\0';

는 틀린 코드입니다. strlen 자체가 '\0' 에 대한 의존도를 가집니다.
즉 id 안에 '\0' 가 들어있지 않다면 당연히 문제를 일으킵니다.

Neogeo - Future is Now.

Neogeo - Future is Now.

klutzy의 이미지

C 문자열을 주의깊게 사용하셔야 할 것 같습니다. C에서는 맨 끝에 NULL을 붙이는 방식으로 문자열을 인식합니다. strlen, strcpy, printf 등 모든 문자열 함수가 이 구조를 이용합니다. 파일이나 소켓 등에서 파일을 읽을 경우 이들 데이터가 'C 문자열'이 아니기 때문에 NULL 같은 처리가 자동으로 되지 않습니다.

read()에서 파일에서 더 이상 읽을 게 없으면(EOF) 0을 리턴합니다. 소켓의 경우에도 마찬가지로 연결이 끊어져 읽을 게 없으면 0이 리턴됩니다.

함수 작동 방식을 완전히 이해하려면 도움말을 찾아보는 수밖에 없습니다. man을 적절히 활용해주세요. 참고로 소켓 통신은 read/write 함수로도 가능하지만, 소켓 전용의 recv/send 함수가 있습니다. 도움말을 볼 때 이 함수도 같이 보는 게 좋을 것 같네요.

freestyle의 이미지

NULL이 아니라 '\0'을 말씀하신 거겠죠?
---------------------------
Go to the U-City

----------------------------------------------------------------------------------------
Don't Feed the Trolls!
----------------------------------------------------------------------------------------

klutzy의 이미지

예 \0으로 써야 맞겠네요. 감사합니다. :) 예전에 C FAQ에서 본 것 같아 찾아봤더니 지적해주신 대로네요. http://cinsk.org/cfaqs/html/node7.html#5.9

dorado2의 이미지

fgets(id,20,stdin);
id[(strlen(id)-1)]='\0';

원 코드에서 위 부분은 fgets에 따라오는 줄바꿈 character(\n)를 없애려고 사용하신 것 같네요.

Richard Stevens의 Unix Network Programming 책을 추천드립니다.
궁금하신 대부분의 내용과 그 이유를 다루고 있으니 큰 도움이 되실 겁니다.

댓글 달기

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