다시 질문올립니다. 간단한 소켓프로그램 파이프 깨짐현상!!이게 뭐야~

dbckdgns의 이미지

답변 정말진짜 감사드립니다 ^^
제가 질문할때 정확하게 못적어 놓은것같다 다시한번 질문드립니다.
서버와 클라이언트 1:1 관계 소켓프로그램이구요. read write 하나씩만 있는 간단한 프로그램입니다. 소켓프로그램 책 첫부분에 있는 예제구요.
이전에 파이프깨짐 현상이라고 한번 올렸었는데요.

파이프깨짐 현상은 클라이언트에서만 나타났습니다.

현재 어느 친절하신분의 가르침으로인해 파이프깨짐 이라는 말은 클라이언트 쪽에서 안나오는데요. 서버쪽에서는 파이프깨짐이라는 말은 이전에도 안나왔구요 지금도 나오진 않구요. 하지만 데이터가 제대로 전달이 되질 않네요.

소스를 보시면 서버쪽에서는 소켓을 생성하고 listen함수를 통해서 클라이언트가 접속하길 기다리고 접속을하면 성공했다고 표시하면서 데이터를 받고 줍니다 . 그리고 연결 종료하구요

클라이언트 쪽에서는 소켓생성후 connect함수를 통해서 접속을 하고 데이터를 주고 받고 연결을 종료합니다.
반복도 없고 그냥 각자가지고 있는 배열들을 보내고 받고 하는것이 끝입니다. 간단하죠?

근데 예전엔 처음실행할때는 주고 받고 한번씩하고 정상적으로 끝났는데 두번째부터 클라이언트가 메세지를 보내면 정상적인 응답을 받지 못하고 파이프 깨짐현상이라는 말이 나오면서 클라이언트는 프로그램이 종료되었습니다. 이때 서버쪽은 연결을기다립니다라는 메세지.. 즉 listen 함수가 대기상태로 계속 대기하고 있구요. 서버가프로그램이 종료되지 않았습니다.

이제 어느 친절한 분의 답변으로 signal(SIGPIPE, SIG_IGN) 이라는 문장을 서버쪽이나 클라이언트쪽에 다 넣어서 파이프 깨짐 현상을 무시했습니다. 이제 파이프깨짐현상이라는 말은 나오지 않지만 이전과 변한것은 없습니다. 서버는 여전히 연결을 기다리는 중이라는 메세지와 함께 계속기다리고 있구요.

제 생각으로는 이미 한번 수행할 때는 잘 실행된 것으로 보아서 함수쪽에 이상은 없는것같은데요 .
서버가 계속기다리는 중이라는 메세지는 listen 함수를 수행을 못한다는 말인것같은데 이는 클라이언트쪽에서 connect함수가 제대로 전달이 되지 않았다는 뜻인것같고.. 함수가 이상이 없다면
내부적인 연산에 이상이 있는건가요? 이렇게 간단한것도 실행이 안되면 앞으로 어떻게 공부를 해나가라고...

긴글읽어주시느라 감사합니다. 답변주신분들 정말 다시한번 감사드리며 한번만더 도움주세요. 부탁드립니다

==================서버=========
#include
#include
#include
#include
#include
#include
#include
#include

#define PORT 55000
int main()
{
signal(SIGPIPE, SIG_IGN);
int server_socket;
int client_socket;

struct sockaddr_in server_address;
struct sockaddr_in client_address;

int client_address_size;
char toClient[]="Hello Clinet !!\n";
char fromClient[100];

server_socket=socket(AF_INET, SOCK_STREAM, 0);
printf("Server socket create!!!\n");
memset(&server_address, 0, sizeof(server_address));

server_address.sin_family=AF_INET;
server_address.sin_addr.s_addr=htonl(INADDR_ANY);
server_address.sin_port=htons(PORT);

bind(server_socket, (struct sockaddr*) &server_address, sizeof(server_address));

listen(server_socket, 5);
printf("Wait Client...\n");
client_address_size = sizeof(client_address);

client_socket = accept(server_socket, (struct sockaddr*) &client_address,
&client_address_size);
printf("Client Connect !!!\n");

read(client_socket, fromClient, sizeof(fromClient));
printf("From Client Message : %s \n", fromClient);

write(client_socket, toClient, sizeof(toClient));
printf("To Client Message: %s \n", toClient);

close(client_socket);
return 0;
}
=============클라이언트====

#include
#include
#include
#include
#include
#include
#include
#include

#define PORT 55000
main()
{
signal(SIGPIPE, SIG_IGN);
int clientSocket;
struct sockaddr_in server_address;
char toServer[]= "Hello Server!!! I'm Client!\n";
char fromServer[100];

clientSocket = socket(AF_INET, SOCK_STREAM, 0);
printf("Create Client Socket !!\n");

memset(&server_address, 0, sizeof(server_address));

server_address.sin_family=AF_INET;
server_address.sin_addr.s_addr=inet_addr("127.0.0.1");
server_address.sin_port=htons(PORT);

connect(clientSocket, (struct sockaddr*) &server_address, sizeof
(server_address));
printf("Connect Server!!\n");

write(clientSocket, toServer, sizeof(toServer));
printf("To Server Message : %s \n", toServer);

read(clientSocket, fromServer, sizeof(fromServer));
printf("From Server Message : %s \n", fromServer);

close(clientSocket);
return 1;
}

Hyun의 이미지

소스부분을 <code>, </code>로 감싸주시면 저도 실행해보겠는데...
아... 긴긴 밤... 심심하네요.

harisoo의 이미지

코딩의 기본은 에러체크에 있습니다.
각 함수를 호출후 에러체크를 하지 않군요.
또한 서버측 코드를 보아서는 서버소켓(server_socket)을 닫아주지 않네요.

익명 사용자의 이미지

일단 서버가 1번 실행하고 종료하도록 되어 있군요.
다수번(또는 다수 클라이언트접속) 수행하기 위해서는
...accept()..
.............
...close()..
이 부분이 루프로(loop) 작성되어야 할것입니다.

* 파이프깨짐?
소켓은 프로세스간 통신 메카니즘의 확장으로 볼 수 있습니다.
전형적인 유닉스의 프로세스간통신(IPC라고 하지요) 메카니즘은 파이프입니다.
이러한 관습(?)에 힘입어, 소켓에서도 그 연결이 끊기는 경우 파이프가 끊겼다느니, 깨졌다느니, broken pipe등의 메시지를 사용합니다.

파이프깨짐은 바로 통신의 종결을 의미합니다.
통신이 끊김은 어떻게 감지하는가? 보통 3가지 방법이 있을 수 있습니다.
1) 상태검사 : 소켓도 파일로 간주하므로, 파일의 상태정보를 읽어봅니다. 소위 bad file number등의 에러가 있는지를 검사
2) 읽어 보기 : 읽어 보면 알 수 있습니다. 읽었을때, 0(zero)이 리턴된다면, 원격지가 끊은 것입니다.
3) 써보기 : write해보면 알수 있습니다. write()를 호출했을때, 실제로는 커널(운영체제)에서 write()의 내부동작을 수행하는데, 이때, 원격지가 연결을 끊은 상태이면, 커널은 응용프로그램에게 "야 파이프 끊겼다~ "라는 메시지를 전달합니다. 이는 일단은 시그널(signal)로 전달하게됩니다. 즉, SIGPIPE라는 시그널을 사용자 프로세스에게 보냅니다. 우리가 유닉스 프로그램에서 시그널관련 루틴을 전혀 달지 않아도 기본적으로 시그널핸들러들이 동작하게됩니다. 이는, 유닉스의 기본철학입니다. 전형적인 시그널핸들러의 예제로 Ctrl+C이지요. 프로그램죽일때 누구나, 애용하는 시그널 보내는 키조작이지요. 물론, 기본 시그널핸들러를 수행하지 않고, 사용자가 정의한 시그널핸들러를 수행하게 할 수도 있습니다. signal()이라는 시스템호출을 통해서 할 수 있지요. 특별히, signal()함수에 SIG_IGN을 넣으면, 해당시그널을 무시하도록 하는 핸들러가 수행됩니다.
여기서 주의할 사항은 해당시그널을 무시했다고 원격지가 끊은 연결이 다시 재연결되고 하거나 하지는 않겠지요? 당연히, 이 경우에 write()함수의 리턴값이 -1이되며, errno를 찍어보면 EPIPE등 파이프관련 에러번호가 세팅될것입니다. 당연히, 에러 처리해야지요.

SIGPIPE가 안뜬다? 운이 좋게도 write()를 호출하지 않아서라고 보면됩니다. 뜨게끔하려면, 원격지(클라이언트/서버)가 먼저 끊게하고 write()한번 호출하면 됩니다. 이는 write()와 sigpipe의 관계를 보이기 위한 어거지 예시입니다.

* 그럼 원격지가 끊은 것을 아는 방법은 3가지가 있는데, 로컬이 끊은 것은 어떻게 아는가? 아.... 우문 현답으로 그냥 압니다.

Fe.head의 이미지

아래가 서버 소스인데..
이부분 이상합니다.
받은 것을 그

server_socket=socket(AF_INET, SOCK_STREAM, 0);  // AF_INET 이 아니라 PF_INET

write(client_socket, toClient, strlen(toClient)); // 문자열을 보낸다면 sizeof() 가 아니라 strlen()

int read_size = 0;
...
...
read_size = read(client_socket, fromClient, sizeof(fromClient));
fromClient[read_size] = '\0';

이런식으로 읽어들인 사이즈를 알아내서 해당 사이즈만큼 출력 해야 함.
-----------------------
과거를 알고 싶거든 오늘의 네 모습을 보아라. 그것이 과거의 너니라.
그리고 내일을 알고 싶으냐?
그러면 오늘의 너를 보아라. 그것이 바로 미래의 너니라.

고작 블로킹 하나, 고작 25점 중에 1점, 고작 부활동
"만약 그 순간이 온다면 그때가 네가 배구에 빠지는 순간이야"

ymir의 이미지

setsockopt 로 SO_REUSEADDR 를 추가해 주세요.

setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (int)sizeof(opt));

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

댓글 달기

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