소켓 프로그래밍 part 2~4 TCP/IP

TCP/IP 소켓 프로그램의 기본적 예제

                     대략적 구조
Server ------------------------------Pipe-------------------------------------Client

socket 함수                                                                                       socket 함수
      |                                                                                                     |
bind 함수                                                                                          Connect 함수
      |                                                                                                     |
listen 함수                                                                                               |
      |                                                                                                     |
accept 함수                                                                                               |
      |                                                                                                     |
read,write                                                                                          read,write
send,recv함수                                                                                     send,recv함수
      |                                                                                                      | 
  소켓닫기                                                                                            소켓닫기


세부사항

<SERVER>

0> 해더파일을 삽입한다
#include<stdio.h> printf();
#include<stdlib.h> exit();
#include<string.h> memset();
#include<arpa/inet.h> socket();.......
#include<sys/types.h>      ''
#include<sys/socket.h>    ''


1>sockaddr_in 구조체를 선언한다...
ex>struct sockaddr_in server; (타입케스팅 할땐 struct sockaddr *)


2>struct 구조체 안의 변수에 값들을 채워준다,

bind등의 함수가 이 구조체의 값을 사용한다

sockaddr_in 구조체의 내부 변수들은 다음과 같이 설정해 준다

ex>
memset(&server,0,sizeof(server)); //구조체 할당하기전에 먼저 초기화
server.sin_family=AF_INET;    //IP의 성격 설정 대부분 ip4를 사용하므로 이렇게 설정
server.sin_port=htons(atoi(argv[1])); //host->Network (type short)
server.sin_addr.s_addr=htonl(INADDR_ANY); //host -> Network (type long) 일단 그냥 외우자

INADDR_ANY는 현재 자신의 IP주소를 말한다 지금 설명하는 프로그램은 서버이므로 자기 자신의
IP를 저장하고 있어야 한다

 
3>소켓을 만들어 준다

(listen함수에서 만들어진 큐을 제어하는 소켓이다 클라이언트와 연결되 작업하는그런 소켓이
아님을 명심하자)

       if((sockid=socket(AF_INET,SOCK_STREAM,0))==-1){
               perror("Socket Created ERROR");
               exit(1);
               }

아래는  man 페이지 수정/추가>

소켓은 지시된 통신 semantics를 지정하는 type 을 갖는다.  현재 정의된 타입은 다음과 같다:

      SOCK_DGRAM  <UDP>
             데이타그램 지원

      SOCK_STREAM    레코드 경계를 보호하진 않는다.  스트림 소켓은 모든 데이타가 그것으로  송수신 되기전에 접속 상태이어야한다.  <TCP/IP>
 
에러가 생겼을때 socket함수는 -1을 리턴 한다는걸 알수있다..
아래껏도 대부분 그렇다

4>bind 함수를 만들어 준다,각 주소로 연결하는 함수


       if(bind(sockid,(struct sockaddr *)&server,sizeof(server))==-1){
               perror("Socket Bind ERROR");
               exit(1);
       }

bind(소켓 파일디스크립터,sockaddr_in 구조체 주소
(꼭 타입 케스팅 할것!), 구조체의 크기);

여기서 소켓 파일 디스크립터란(또는 id?) 그리고 타입케스팅 할때 _in 빼자

5>대기열 생성

       if(listen(sockid,5)==-1){
               perror("Listen ERROR");
               exit(1);
       }

간단한 함수...
listen(소켓 id,대기 큐 갯수);
대기열을 왜 만드냐하면... 클라이언트가 한번에 여러개 접속할수 있으니까...
막 일려올때 순서를 정해서 일을 처리하기 위해서*/

6>연결 허용 accept함수

aceept함수는 크기를 줄때 주소로 주어야 한다
또 이함수는 새로운 소켓 id을 반환한다..

추가> 아까 만든 소켓을 대기큐를 제어하는데 쓰이는 소켓
이번에 만들어진 소켓이 정말 데이터를 처리한다*/

       faccept=sizeof(client);//주소 때문에 이렇게 함

               if((sockid2=accept(sockid,(struct sockaddr *)&client,&faccept))==-1){
                       perror("Aceept ERROR");
                       exit(1);
               }

accept함수의 리턴값이 바로 accept함수가 만들어준 새로운 소켓의 파일 디스크립터이다

7>나머지는 파일 입출력과 같다..

이 파일 디스크립터로 네트워크의 호스트에 연결된것이다 이 리턴된 파일 디스크립터 로 일반 표준 입출력
처럼 사용하면 된다(파이프를 연상하면 그나마 비슷할까)*/

       while(1)
       {
               read(sockid2,buf,100);
               printf("%s",buf);
               write(sockid2,buf,100);
       }

8>소켓을 닫는것을 일반 파일과 같게 적용되기도 한다
               close(sockid2);

절대 강조! (나에게 쓰는 메세지)
리턴값 처리해줘야 하는 함수는 socket(),accept() 함수 밖에 없다!!
(이상한거 리턴받아 쓰지 말자!!!!!!!!)

<Client>
(여기서 숫자는 서버의 단계 숫자)

일단 0~3까지의 순서는 SERVER와 같다
4~6의 과정은 쓰지 않는다
그러므로 생략 중간에 Connect함수쓰는거 빼면
7~8번째도 같다

이번엔 귀찮으니깐 Connect함수만 쓰도록 한다

if(connect(sockid,(struct sockaddr *)&server,sizeof(server))==-1){
    perror("Connect ERROR");
      exit(1);
}
뭐.. 설명이 필어 없을듯 하다 인자는 Bind함수랑 비슷하다(같은건가?)
서버와 연결을 할때 쓰는 함수다

7>
단 read,write쓸때
read 하면 클라이언트에서 받을거고
write하면 클라이언트에서 메세지를 보낸다
라는 약간의 차이가 있다
파일 디스크립터(클라이언트 에게 보넬 입출력 fd) 는 소켓을 생성한 파일 디스크립터에다가
read,write하면 된다

8> 번에 대해서는 뭐 당연하다고 생각하는데로 생각하면 된다

서버와 연결을 할때 쓰는 함수다  자세한건 Manpage~