리눅스 멀티프로세스 소켓 프로그래밍에 대한 질문입니다

ShaYEL의 이미지

에코 클라이언트 프로그램인데요, 자식 프로세스를 만들어서 부모는 수신, 자식은 송신을 담당하도록 만들었습니다. 아래에 코드 전문을 적어놨는데요, 보내는 문자열이 짧을때는 문제가 없는데 문자열이 길어지면 조금 이상하게 작동합니다.

부모 프로세스와 자식 프로세스가 동시에 실행되는것처럼 보인다.. 는건 알겠는데 아래와 같은 경우 정확히 부모 프로세스가 어디까지 실행되고 나서 대기를 하고, 다음 자식 프로세스가 어디까지 실행되고 나서 대기를 하게 되는지, 이런것들이 이해가 잘 안됩니다.

if (pid == 0)
		write_routine(sock,buf);
	else
		read_routine(sock,buf);

이 부분이 정확히 어떤 과정으로 돌아가게 되는 건지 설명해 주시면 감사하겠습니다.

#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define BUFSIZE 30
void error_handling(char *message);
void read_routine(int sock, char *buf);
void write_routine(int sock, char *buf);
 
int main(int argc, char **argv)
{
	int sock;
	pid_t pid;
	char buf[BUFSIZE];
	struct sockaddr_in serv_addr;
	if (argc != 3)
	{
		printf("Usage : ./%s [IP] [Port] \n",argv[0]);
		exit(1);
	}
 
	sock = socket(PF_INET,SOCK_STREAM,0);
	if (sock < 0)
		error_handling("socket() error");
 
	memset(&serv_addr,0,sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
	serv_addr.sin_port = htons(atoi(argv[2]));
 
	if (connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0)
		error_handling("connect() error");
	else
		printf("Connected....................\n");
 
	pid = fork();
	if (pid == 0)
		write_routine(sock,buf);
	else
		read_routine(sock,buf);
 
	close(sock);
	return 0;
}
 
void read_routine(int sock, char *buf)
{
	int recv_len;
	while (1)
	{
		recv_len = read(sock,buf,BUFSIZE-1);
		if (recv_len == 0)
			return;
		else
			printf("Message from server: ");
 
		while (recv_len == BUFSIZE-1)
		{
			printf("%s",buf);
			recv_len = read(sock,buf,BUFSIZE-1);
		}
		buf[recv_len-1] = 0;
		printf("%s\n",buf);
	}
}
 
void write_routine(int sock, char *buf)
{
	while (1)
	{
		fgets(buf,BUFSIZE-1,stdin);
		if (!strcmp(buf,"q\n") || !strcmp(buf,"Q\n"))
		{
			shutdown(sock,SHUT_WR);
			return;
		}
		write(sock,buf,strlen(buf));
	}
}
 
void error_handling(char *message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(1);
}
ShaYEL의 이미지

올려놓고 보니... 주석이라도 달아서 올릴걸 그랬나요 orz

jick의 이미지

(1) read는 (당연한 얘기지만) 데이터를 읽은 다음 끝에 널문자('\0')를 붙여주지 않습니다. buf는 main의 로컬 변수니 초기화가 안 되어 있죠. read_routine에서 29자를 읽은 다음 printf를 하게 되면 무슨 일이 일어날지 모릅니다.

(2) 소켓 통신은 스트림 방식이라서, 보내는 쪽이 한번에 보냈다고 받는 쪽이 한번에 받는다는 보장이 안됩니다. 예를 들어 2000바이트를 보낸다면 커널에서 임의로 1000바이트짜리 두 개로 끊어서 보낼 수 있습니다.
그러면 읽는 쪽에서 29바이트씩 끊어 읽으면 중간에 한번 잘리게 되겠죠.
소켓을 읽는 코드는 read가 한번에 한 바이트씩 돌려줘도 동작할 수 있게 짜야 합니다.

댓글 달기

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