1579, 1/79 회원가입  로그인  
   소유
   http://soyu.cafe2.net
   소켓 프로그래밍

http://www.hackerschool.org/HS_Boards/zboard.php?id=Free_Lectures&no=32 [복사]


                  _____                 _______            
                 /  __ \               |___  (_)          
                 | /  \/ ___  _ __ ___    / / _ _ __   ___
                 | |    / _ \| '__/ _ \  / / | | '_ \ / _ \
                 | \__/\ (_) | | |  __/./ /__| | | | |  __/
                  \____/\___/|_|  \___|\_____/_|_| |_|\___|
                                          
------[ Corezine volume 01 - Juli 1999                    
                                
                                Corezine #01
                             ==================

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
                   The *beginners* guide to sockets in C
                               By: xphantom
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=


번역 : Anesra (anesra@hanmail.net)

/*
늘 하는 말이지만 번역상 이상한것이나 무슨 할말이 있으신 분은 저 메일로 보내주시기
바랍니다
*/


당신이 다른 컴퓨터에 연결하기 원한다면 어떻게 프로그램을 만드는가?
당신은 네트워크상에 어떤 정보도 찾을 수 없다. 당신은 맨 페이지에 있는 것을
볼 것인가? 어떤 책을 볼 것인가? 글쎄, 당신은 옳은 장소에 갈 수 있다.
이 문서에서 나는 당신이 C로써  인터넷 어플리케이션을 프로그래밍 할수 있게
도움을 주는 것을 원한다. 이 문서에서 최소한 C에 어느정도 알고있다고 가정하고
그것의 문법과 또한 유닉스 또는 리눅스상에서 사용해본 적이 있다고 가정한다.
이 문서에 포함된 모든 코드와 설명은 glibc 2.07과 libc5.3.12를 사용하는
레드 헷 5.2 상에서 컴파일 되었고 모든 코드들이 잘 수행되었다.
자 이제 함께 해보자


프로그래머에게, 소켓은 low level의 파일 기술자(당신이 사용하는 소켓의
read() 와 write() 함수)와 매우 유사하다. 비록 소켓 그 자체를 생성하는 것이
당신 자신의 하드 디스크로 부터 쓰고 읽는 것과 비교하여 네트워크 연결의
복잡성의 이유로 파일에 읽고 쓰고 여는 것보다 더 복잡할 지라도


대부분 소켓을 사용하기 위해서, 당신은 클라이언트와 서버 쌍이 필요하다. 서버가
하는 일은 특별한 포트에서 기다리고 클라이언트로부터 요청을 받았을 때 어떤
일을 수행하는 것이다. 클라이언트의 일은(명확히) 어떤 것을 하기 위해 프로그래밍
되어진 무슨 일이든 실행하기 위해서 서버에 "ask"를 하는 것이다.



우리는 이 문서에서 *모든* 소켓 타입 함수를 사용하지 않을 것이다. 이것은 초보자를
위한 지도서이기 때문에, 그러나 즐거움을 얻고 당신의 실력을 높이기 위한 정보를 얻기엔
충분할 것이다. 자 이제 몇개의 소켓을 만들어 보자.

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
소켓을 생성 : socket()


당신의 소켓 프로그래밍을 하기 위해서 가장 먼저 해야할 일은 socket()함수를
사용하여 소켓을 생성하는 일이다.

-------

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

int socket(int af, int type, int protocol)

------

'int af'는 소켓 도메인과 주소 패밀리 부분이며. 대부분 두가지를 사용한다.
        AF_UNIX - 한 호스트내에서 상호 통신하기 위해서 사용된다.
        AF_INET - 같거나 또는 다른 DARPA프로토콜(UDP/TCP/IP)를 사용하는 시스템
        간의 상호 통신을 하기 위해서 사용된다.


'int type'은 당신이 사용할 연결의 형태가 무엇인지, 대부분 두가지를 사용한다.
        SOCK_STREAM - 연결 지향적인 소켓을 위해 사용된다. 데이타 전송이 보증되고,
        그렇지 않으면 받은 곳에 의해 에러가 전송될것이다.
        SOCK_DGRAM -  연결이 덜 한 소켓을 위해 사용된다. 데이타 보장이 없이 전송된다.


이 문서에서는 우리는 family AF_INET과 SOCK_STREAM 타입에 중점을 둘 것이다.


'int protocol'은 보통 protocal값이 0이다. 이것은 시스템이 family와 type을 위한
특별한 값의 쌍으로 허락되어진 첫번째 프로토콜을 선택하기위해 허락되어진다.



성공하면, 파일 기술자가 리턴하고, 실패하면 -1을 리턴하고 errno가 그것에 알맞게
설정될 것이다.
------

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

int sockfd /* soon to be socket file descriptor */

   sockfd = socket(AF_INET, SOCK_STREAM, 0)
   /* error checking here */

------

그리고 만일 모든것이 잘 수행되었으면, 우리는 우리가 연결지향적인 기본적인
프로토콜(SOCK_STREAM)을 사용하는 인터넷(AF_INET)을 통해서 사용할수 있는
소켓 기술자를 가진다. protocol(0)은 자동적으로 우리에 의해서 설정된다는 것을 기억하라.

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
당신의 소켓을 사용하기 위한 이름을 주어라 : bind()


좋다, 지금 우리는 우리의 소켓을 생성하였다. 다음으로 할 것은 그거에 어떤일을 할수 있게
하는것이 필요하다. 이름을 사용하기 위해 bind()를 주는것을 시도하라.

------

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

int bind(int sockfd, struct sockaddr *name, int namelen)

------
bind()를 호출하때 인자인, sockfd는 소켓을 위한 파일 기술자이고, socket()을
호출하기 위해 얻는 것이며,  Name은 sockaddr타입 구조체의 포인터이다.
만일 address family가 AF_UNIX(소켓이 생성될때 지정되어진 것이라면)이면,
구조체는 아래와 같이 정의 될 것이다.
------

struct sockaddr {
                u_short sa_family;
                char    sa_data[14];
        };

------
name.sa_family는 AF_UNIT로 되어질 것이다. name.sa_data는 소켓을 할당하기 위해서
사용된 파일 이름의 14byte를 가질것이다. namelen은 데이터 구조를 포함하는 초기화된
길이인 name의 실제 길이로 주어진다.
------

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

struct sockaddr name;
int sockfd;

   name.sa_family = AF_UNIX;
   strcpy(name.sa_data, "/tmp/whatever");

   sockfd = socket(AF_UNIX, SOCK_STREAM, 0)
   /* error checking code here */

   bind(s, &name, strlen(name.sa_data) + sizeof(name.sa_family)
   /* error checking code here */

------
에러 체킹 통지 : bind()가 성공하면 0을, 실패하면 bind()는 -1을 리턴하고
그것에 알맞게 errno를 설정한다.

이제, AF_INET을 사용하는 bind를 호출할때 우리는 다른 구조체를 사용한다.
-----

struct sockaddr_in {
        short int          sin_family;  /* Address family               */
        unsigned short int sin_port;    /* Port number                  */
        struct in_addr     sin_addr;    /* Internet address             */
        unsigned char      sin_zero[8]; /* Same size as struct sockaddr */
    };

------
이것은 조금 더 크고 더 복잡하나 어려운것은 아니다. 아래와 같은
예를 보자.
------

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>

int sockfd, port = 23;
struct sockaddr_in my_addr;

   if((sockfd=socket(AF_INET, SOCK_STREAM, 0)) == -1)
   {
      printf("Socket Error,  
      exit(1);
   }
  
   my_addr.sin_family = AF_INET; /* host byte order */
   my_addr.sin_port = htons(port); /* see man htons for more information */
   my_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* get our address */
   bzero(&(my_addr.sin_zero), 8); /* zero out the rest of the space */

   if((bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
   {
      printf("Bind Error,  
      close(sockfd);
      exit(1);
   }

------

자, 만일 모든 것이 잘 되었다면, 우리의 소켓은 지금 이름을 가질 것이고, 만일
모든것이 잘 되지 않았다면, 에로가 발생할 것이고 프로그램은 종료될 것이다.
조금 작은 메모 -  만일 모든 당신의 프로그램이 다른 컴퓨터에 연결되고,
당신은 전혀 bind()함수의 사용이 필요하지 않을수도 있다(비록 그것이 어떤 것에
손상을 입히지 않는다면). 이 라인 : my_addr.sin_port = htons(port); 은
우리의 포트가 단지 0으로 셋팅함으로써 자동적으로 정해질수 있고, 클라이언트 프로그램은
좋을 것이나, 당신이 그것이 무슨 포트를 사용하는지 알수 없기 때문에 서버 프로그램을
위해서는 나쁘다.


=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
원격 연결을 위해 사용 : connect()


만일 당신이 원격 머신에 연결하기 원한다면, connect()함수를 사용하여야 한다.
------

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

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);

------
sockfd는 socket()을 호출하고 나서 리턴되는 우리의 친근한 소켓 파일 기술자이다.
serv_addr는 목적지 포트와 IP주소를 가지고 있는 sockaddr구조체이다.
addrlen은 sizeof(struct sockaddr)로 설정할수 있다.
자 다른 예제를 보자.
------

#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>

#define DEST_IP   "132.241.5.10"
#define DEST_PORT 23

main()
{
int sockfd;
struct sockaddr_in dest_addr;   /* will hold the destination addr */

   sockfd = socket(AF_INET, SOCK_STREAM, 0); /* do some error checking! */

   dest_addr.sin_family = AF_INET;        /* host byte order */
   dest_addr.sin_port = htons(DEST_PORT); /* short, network byte order */
   dest_addr.sin_addr.s_addr = inet_addr(DEST_IP);
   bzero(&(dest_addr.sin_zero), 8);       /* zero the rest of the struct */

   connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));
   /* error checking code here */
  /* more code
.
.
.
*/
}

------
또, connect()는 성공하면 0을 리턴하고 실패하면 -1을 리턴하고 errno를 설정한다.
당신은 bind()함수가 빠진걸 눈치챌지 모른다. 우리는 연결하기 위해 어떤 포트를
사용할지 모르기 때문에, 이것과 같은 경우 우리가 연결하고자 하는 포트만을 사용한다.
(역자 주: 클라이언트에서 어떤 포트를 사용할지 정확히 정해지지 않았기 때문에 bind()를
뺐다는 말.)

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
호출을 사용하기 위해서 기다림 : listen()


말했듯이 우리는 어떤 포트의 서버 프로그램을 만들기 원한다. 우리는 우리가 알지 못하는
어떤 연결이 들어오는 것을 위해 대기하기 위한 어떤 방법이 필요하다.
그것이 listen()함수이며 아래와 같이 동작한다.(그것은 잘 알지도 모른다;))

------

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

int listen(int sockfd, int backlog);

------
sockfd는 또 우리의 소켓 파일 기술자이다.
backlog는 우리가 한번에 받을수 있는 연결의 수이다.


또, 일상적으로 , listen()은 실패하면 -1을 리턴하고 errno를 셋팅한다.
이제 이런 경우에 우리는 listen()을 호출하기 전에 bind()호출이 필요할 것이다.
(우리는 그들이 추측할수 있게 만들지 않고 연결하기 위한 사람을 위해 특정한
포트를 원한다.)
우리의 함수는 아래와 같은 순서를 가진다.
------

socket(); /* to create out socket file descriptor */
bind(); /* to give our socket a name */
listen(); /* listen for connection */

------

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
연결을 받아 들이기 위해 사용 : accept()


됬다, 이것은 어디에.. 음.. 웃기게 시작하자. 어떤 사람이 당신이 기다리고 있는
포트에 연결하기를 시도했다면, 당신은 지금 그 연결을 받아들일 필요가 있고
accept()는 그것을 수행할것이다.(누군지 알어? ;))

------

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

int accept(int sockfd, void *addr, int *addrlen);

------
또, sockfd는 우리의 친근한 파일 기술자이다.
addr은 종종 사용된 struct sockaddr_in의 구조체를 가리키는 포인터이다.
addrlen은 설정할 것이다 : sizeof(struct sockaddr_in)
에러가 발생할때 리턴되는 값을 추측할수 있겠는가?... 당신은 그것을 알것이다....
-1을 리턴하고 errno를 설정한다. E.G:
------

#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>

#define MYPORT 1500    /* the port users will be connecting to */
#define BACKLOG 5      /* how many pending connections queue will hold */

main()
{
int sockfd, new_fd;  /* listen on sock_fd, new connection on new_fd */
struct sockaddr_in my_addr;    /* my address information */
struct sockaddr_in their_addr; /* connector's address information */
int sin_size;

   sockfd = socket(AF_INET, SOCK_STREAM, 0); /* do some error checking! */

   my_addr.sin_family = AF_INET;         /* host byte order */
   my_addr.sin_port = htons(MYPORT);     /* short, network byte order */
   my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
   bzero(&(my_addr.sin_zero), 8);        /* zero the rest of the struct */

   /* did you remember your error checking? */
   bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));

   listen(sockfd, BACKLOG);

   sin_size = sizeof(struct sockaddr_in);
   new_fd = accept(sockfd, &their_addr, &sin_size);

------
우리는 모든 send()와 recv() 호출을 위해 new_fd 소켓 기술자를 사용할 것이라는 것을
알아라. 만일 당신이 오직 한 연결만을 받는다면, 당신이 원한다면 당신은 같은 포트에
더 이상 연결되는 것을 막기위해 원본 sockfd를 close()할수 있다.

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
우리가 이야기 하기 위해서 필요한것들 : send() and recv()


이제, 우리는 소켓을 생성하였고, 이름을 주었고, 연결을 받아들이기위해 기다렸고,
send()와 recv()로써 서로 정보를 교환하기 위한 마지막 시간이다.
------

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

int send(int sockfd, const void *msg, int len, int flags);
int recv(int sockfd, void *buf, int len, unsigned int flags);

------
send():
sockfd - 소켓 파일 기술자
msg - 보내기 위한 메세지
len - 보내기 위한 메세지의 크기
flags - 더 많은 정보를 위해서 'man send'를 읽어봐라, 그것은 지금을 위해서 0으로 세팅한다. :)


recv():
sockfd - 소켓 파일 기술자
buf - 받기 위한 데이타
len - buf의 크기
flags - send()의 플래그와 같다.

send() example:
------

char *msg = "Hey there people";
int len, send_msg;

/* code to create(), bind(), listen() and accept() */

len = strlen(msg);
bytes_sent = send(sockfd, msg, len, 0);

------
recv() example:
------

char *buf;
int len, recv_msg;

/* code to create(), bind(), listen() and accept() */

len = strlen(buf);
recv_msg = recv(sockfd, buf, len, 0);

------
그리고 또, send()와 recv()는 에러가 생기면 -1을 리턴하고 errno를 설정한다.
만일 당신이 SOCK_DGRAM 형태를 사용한다면 sending와 receiving 데이타를 위해서
sendto()와 recvfrom()함수를 사용해야 한다.

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
당신과 이야기해서 즐거웠다 : close() 와 shutdown()


한번 당신은 데이터 전송을 마쳤으면, 그것은 간단히 소켓을 닫음으로써 연결을
끝낸다.
------

#include <stdio.h>

/* all you code */

close(sockfd);

------
정말 간단하지 않은가? 만일 당신이 연결에 대해서 더 많은 통제를 원한다면
shutdown()함수를 사용해라.
------

int shutdown(int sockfd, int how)

------

how를 위해서는 세 개의 다른 값들이 있다.
   1 - no more revc()'s allowed
   2 - no more sends are allowed
   3 - no more send()'s or recv()'s allowed (same as close())
   1 - 더이상 recv()를 허락하지 않는다.
   2 - 더 이상 send를 허락하지 않는다.
   3 - 더이상 send()또는 revc()를 허락하지 않는다(close()와 같다)


그것은 쉽다. 당신은 지금 소켓을 생성하고, 그것에 이름을 주고, 연결을 위해서
기다리며, 연결을 받아들인뒤 다른 컴퓨터와 연결하고 그리고 소켓을 닫는다.
어렵지 않지? 엉?

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
너는 누구냐 : getpeerbyname()

그리고 나서 당신은 당신에게 연결한 자가 누구인지 알기를 원하지 않는가? 글쎄
당신은 행운아다! 단지 그 목적을 위한 함수가 여기에 있다.
------

#include <sys/socket.h>

int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);

------

sockfd - 우리의 친근한 소켓 파일 기술자이다
addr - 'struct sockaddr' 또는 'struct sockaddr_in'을 가리키는 포인터이다
addrlen - 만들어야 한다 : sizeof(struct sockaddr)


이런 이런, getpeerbyname()또한 에러가 발생하면 -1을 리턴하네. 누구나 이것을 추측할수
있겠지? 만일 이것이 잘 동작한다면, 당신은 지금 당신에게 연결한 사람의 주소를
얻을 수 있고 그리고 inet_ntoa() 또는 gethostbyaddr()를 사용하여 더 많은 정보를
얻을 수 있고, 여기에 대해서더 많은 것을 알고 싶으면 identd이 동작하지 않는다면
그들의 로긴 네임을 알수 없을것이다.
이것에 대한 더 자세한 정보를 알고싶다면 RFC 1413을 읽어봐라.


=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
나는 누구인가 : gethostname()

됬다, getpeerbyname()은 쉬웠다, 충분히, gethostname()는 더 쉽다.
------

#include <unistd.h>

int gethostname(char *hostname, size_t size);

------
hostname - 리턴될 호스트 이름을 저장할 수 있는 char형태의 배열
size - 배열에 의해 언급된 이상의 크기

        
이것은 컴퓨터의 이름을 리턴한다. 당신의 프로그램이 돌아간다면 당신의 IP address
를 gethostbyname()을 사용함으로써 알수 있다. 또한 실패하면 -1을 리턴한다.

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
너의 IP는 무엇이냐?


충분히, 사용할 정보를 얻으로 가자. 오케? 우리는 전체 프로그램, DNS program,
을 만들기 위해서 처음할 것을 만들자. DNS 또는 "Domain Name Service"는
그것의 "human-readbale"주소를 사용함으로써 기계의 IP 주소를 얻을 수 있는 방법이다.

$ telnet microsoft.com
  Trying 206.163.24.176 (not the real address but I'm too lazy to try :))


충분히 무엇인가를 추측한다, 먼저 텔넷 프로그램은 microsoft.com의 DNS를 체크하고
그것의 IP를 얻어온다. 이제, 이것은 netdb.h에서 찾을 수 있는 gethostbyname()함수를
사용한다.
------

#include <netdb.h>
    
struct hostent *gethostbyname(const char *name);

------
이것을 봄으로써 당신은 'struct hostend'를 호출하는 구조체를 사용하는 것을 볼수 있다.
------

struct hostent {
        char    *h_name;
        char    **h_aliases;
        int     h_addrtype;
        int     h_length;
        char    **h_addr_list;
    };
#define h_addr h_addr_list[0]

------

이 구조체는 아래와 같은 조각들로 되어있다.

h_name - 호스트의 공식적인 이름
h_aliases - 호스트를 위한 널로 끝나는 교대의 이름의 배열.
h_addrtype - 리턴되는 어드레스 타입; 주로 AF_INET.
h_length - bytes로 된 주소의 길이
h_addr_list - 호스트를 위한 0으로 끝나는 네트워크 주소의 배열.
              호스트 주소는 Network Byte Order이다.
h_addr - h_addr_list에 있는 첫번째 주소


gethostbyname()은 struct hostent를 채우기 위한 포인터를 리턴한다, 그렇지 않고
에러가 발생하면 NULL을 리턴한다.(그러나 errno는 설정되지 않는다-h_errno가 대신
설정된다. 더 많은 도움을 얻기 위해선 'man herrno'를 봐라) 이제 우리의 DNS프로그램을
만들어 보자.

------

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

int main(int argc, char *argv[])
{
   struct hostent *h;

   if (argc != 2) {  /* error checking on the command line */
      fprintf(stderr,"Usage: getip <host name>\n");
      exit(1);
   }

   if ((h=gethostbyname(argv[1])) == NULL) {  /* get the host info */
      herror("gethostbyname");
      exit(1);
   }

   printf("Host name  : %s\n", h->h_name);
   printf("IP Address : %s\n",inet_ntoa(*((struct in_addr *)h->h_addr)));

   return 0;
}

------

그리고 이제 보자, 작고 쉽지 않은가, 단지 우리는 이렇게 만들고, 그것을 다음과 같이
컴파일 시키면 된다
:gcc -o getip getip.c(우리는 저것을 getip.c로 저장했다고 가정한다 :))

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=

클리어언트 와 서버 프로그램

오케, 마지막으로 자그마한 , 그리고 다소 무의미한, 클리이언트-서버 어플리케이션에
대해서 토론해보자. 오직 이것에 대한 목적은 서버에 연결하고, 이미 지정된 스트링을
받고, 그리고 연결을 끈기 위한 사용자를 위해서 이다.
그러나 그것은 어떤 점을 얻을 수 있으며, 나는 당신이 이것으로 부터 더 유용한 것을
만들 수 있을 것이다. ..오, 당신은 그것에 에러체킹을 할수도 있다.:)
------

<++> socket/server.c
/* SERVER PROGRAM */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>

#define PORT 1500      /* the port users will be connecting to */

#define BACKLOG 5      /* how many pending connections queue will hold */

main()
{
int sockfd, new_fd;  /* listen on sock_fd, new connection on new_fd */
struct sockaddr_in my_addr;    /* our address information */
struct sockaddr_in their_addr; /* their address information */
int sin_size;

   sockfd = socket(AF_INET, SOCK_STREAM, 0);
   /* remember to error check (-1 on error) */

   my_addr.sin_family = AF_INET;         /* host byte order */
   my_addr.sin_port = htons(PORT);     /* short, network byte order */
   my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
   bzero(&(my_addr.sin_zero), 8);        /* zero the rest of the struct */

   bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));

   listen(sockfd, BACKLOG)
  

   while(1) {  /* start out accept() loop */
      sin_size = sizeof(struct sockaddr_in);
      new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)
      printf("server: got connection from  
      fork(); /* this is the child process */
         send(new_fd, "Hello, world!\n", 14, 0)
         close(new_fd);
         exit(0);

         while(waitpid(-1,NULL,WNOHANG) > 0); /* clean up child processes */
   }
}

/* END SERVER PROGRAM, REMEMBER TO DO YOUR ERROR CHECKING */
<--><++> socket/client.c
/* CLIENT PROGRAM */

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

#define PORT 1500    /* the port client will be connecting to */

#define MAXDATASIZE 100 /* max number of bytes we can get at once */

int main(int argc, char *argv[])
{
int sockfd, numbytes;  
char buf[MAXDATASIZE];
struct hostent *he;
struct sockaddr_in their_addr; /* connector's address information */

   if (argc != 2) {
      fprintf(stderr,"Usage: client <host name>\n");
      exit(1);
   }

   he = gethostbyname(argv[1]);  /* get the host info */
   /* did you check for errors? */

   sockfd = socket(AF_INET, SOCK_STREAM, 0);

   their_addr.sin_family = AF_INET;      /* host byte order */
   their_addr.sin_port = htons(PORT);    /* short, network byte order */
   their_addr.sin_addr = *((struct in_addr *)he->h_addr);
   bzero(&(their_addr.sin_zero), 8);     /* zero the rest of the struct */

   connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr));

   numbytes = recv(sockfd, buf, MAXDATASIZE, 0);

   buf[numbytes] = '\0';

   printf("Received:  

   close(sockfd);

   return 0;
}

/* END CLIENT...YOU CHECKED FOR ERRORS RIGHT? :) */
<-->

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=

충분히, 나는 그것이 지금 더 많이 나아졌으리라 생각한다. 이것은 소켓 프로그래밍을
위한 완벽한 가이드라고 생각하지 않는다, 실제적으로, 그것은 시작하는 것으로 부터
매우 멀어져있고 고의로 어던 문제도 없지 않다. 이 주제에 대해서 더 많이 알고싶은
사람들을 위해 아래 맨 페이지를 볼 것을 제안한다.

socket, bind, connect, perror, herror, listen, accept, send, recv,  close,
shutdown, getpeername, getsockname, gethostbyname, gethostbyaddr and
getprotobyname.


당신은 또한 아래와 같은 좋은 책들을 읽어 봐도 좋다.

------

Internetworking with TCP/IP, volumes I-III by Douglas E. Comer and David
L. Stevens. Published by Prentice Hall. Second edition ISBNs: 0-13-468505-9,  
0-13-472242-6, 0-13-474222-2. There is a third edition of this set which
covers IPv6 and IP over ATM.  

Using C on the UNIX System by David A. Curry. Published by O'Reilly &
Associates, Inc. ISBN 0-937175-23-4.

TCP/IP Network Administration by Craig Hunt. Published by O'Reilly &
Associates, Inc. ISBN 0-937175-82-X.

TCP/IP Illustrated, volumes 1-3 by W. Richard Stevens and Gary R. Wright.
Published by Addison Wesley. ISBNs: 0-201-63346-9, 0-201-63354-X,
0-201-63495-3.

UNIX Network Programming by W. Richard Stevens/ Published by Prentice
Hall. ISBN 0-13-949876-1.

-------
이것에 대한 완벽한 실정을 알고 싶은가? 아래의 RFC들을 봐라:
------

RFC-768 -- The User Datagram Protocol (UDP)
(ftp://nic.ddn.mil/rfc/rfc768.txt)

RFC-791 -- The Internet Protocol (IP)
(ftp://nic.ddn.mil/rfc/rfc791.txt)

RFC-793 -- The Transmission Control Protocol (TCP)
(ftp://nic.ddn.mil/rfc/rfc793.txt)

RFC-854 -- The Telnet Protocol
(ftp://nic.ddn.mil/rfc/rfc854.txt)

RFC-951 -- The Bootstrap Protocol (BOOTP)
(ftp://nic.ddn.mil/rfc/rfc951.txt)

RFC-1350 -- The Trivial File Transfer Protocol (TFTP)
(ftp://nic.ddn.mil/rfc/rfc1350.txt)

------

충분히, 나는 이것이 인사하기 위한 시간과 소켓 프로그래밍안으로 행복한 여행을
할 것이라 추측한다. 내가 말하기 전에, 이것은 완벽한 매뉴얼은 *아니다*
그것은 오직 작은 입문서 일뿐이다. 아마도 여기에 내가 실수한 많은 에러도 있을
것이다. 오 충분히, 그것은 인생과 같다, 나는 결코 어떤 대가를 바라지 않는다.
아마도 곧 나는 SOCK_DGRAM 타입의 문서를 만들 것이고, 다른 기이한 소켓과 같다.
"그것을 함께, 즐겨라.

~xphantom


//역자후기
번역은 꽤 오래전에 해놓았으나 번역이 너무 이상한 듯해 두고있었지만
그래도 다른 사람을 위해서(영어를 보기만 해도 닭살이 돋는 사람들)을 위해
이렇게 올립니다:)



  Hit : 14042     Date : 2003/09/11 05:41
[불법/스팸글로 신고하기]



    
sasinkilli ㅡㅡ 짱입니다요 2003/09/11  
ljwking 도서관에 있는거 아닌가요^^? 2003/09/12  
luckyhuni 솔직히 모르겟다 ㅠ 2008/07/18
yooadocjon 난 언제쯤 이해할 수 있을까 2011/07/17  
lawsoul 아 어렵습니다..확실히

다음에 한번 재참조 해보겠습니다.

비록오래된 글이지만 감사합니다.
2012/01/16  
1579   리눅스 명령어 마스터 1[78]     소유
09/02 32487
1578   리눅스 명령어 마스터 2[27]     소유
09/03 19081
1577   유치원 만화 크게보기[11]     소유
09/03 16533
1576   리눅스 명령어 마스터 3[13]     소유
09/04 14914
1575   좋은 비밀번호란???[24]     소유
09/04 17015
1574   리눅스 명령어 마스터 4[13]     소유
09/05 14493
1573   리눅스 명령어 마스터 5[8]     소유
09/06 13414
1572   레이스 컨디션(경쟁 조건)[14]     소유
09/06 12734
1571   리눅스 명령어 마스터 6[7]     소유
09/08 12276
1570   리눅스 명령어 마스터 7[8]     소유
09/09 12303
1569   [특별] find 명령어[7]     소유
09/09 13846
1568   ↓보충. 올바른 검색 조건으로, find명령어를 사용하자.[13]     yl
09/09 11880
1567   리눅스 명령어 마스터 8 [마지막][44]     소유
09/10 12362
1566   시스템 리소스 99%에 도전하자!![18]     DarkSlayer
09/10 14898
1565     [re] 추가 설명[9]     暴走天使
09/11 8688
1564   네트워크 개념 휘어잡기 1[24]     소유
09/10 17363
1563   허접 팁 Setuid 쉽게 찾기 -_-;[3]     ttongfly
09/10 12920
1562   Linux Root 패스워드 분실시 조치 방법[9]     h41d35
09/10 11598
1561   네트워크 개념 휘어잡기 2[16]     소유
09/11 13026
  소켓 프로그래밍[5]     소유
09/11 14041
1 [2][3][4][5][6][7][8][9][10]..[79]

Copyright 1999-2021 Zeroboard / skin by Hackerschool.org / Secure Patch by Hackerschool.org & Wowhacker.com