노트 필기 잡동사니

- 서버는 PORT번호를 보통 고정시킨다. 일반적으로 0~1023 포트는 관리자 권한 없이 포트를 열 수 없다. 그러므로 될 수 있으면 0~1023번 포트는 사용하지 않도록 한다. 단 클라이언트의 경우 안쓰는 포트 중 하나를 랜덤으로 사용한다.

- 네트워크는 이기종 끼리도 통신이 가능해야 한다.

- 포트가 끊기는 데에는 어느 정도 시간이 필요하다.

- TCP/IP의 표준 데이터 저장 방식은 Big-Endian이다.(함수들도 해당) 인텔의 대부분 컴퓨터는 Little-Endian 구조이므로 데이터를 처리할 때 뒤집어 주어야 하고, 통신해 받은 데이터도 뒤집어 주어야 한다. 이들은 함수로 제공되어 있다.

- htonl : Host to Network Long, Long은 데이터 타입을 말하며, ip 주소를 처리해 줄 때 사용한다. Little -> Big

-> INADDR_ANY는 0의 값을 갖고 있다. htonl에 0의 값(혹은 INADDR_ANY)을 적으면 자동으로 유저의 ip가 들어간다.

서버는 IP가 고정되어 있어야 하므로 해당 함수를 이용함에 주의해야 하지만, 클라이언트는 유저마다 ip가 다르므로 클라이언트의 주소를 처리할 때 쓸 수 있다.

- htonsHost to Network Short, Short는 데이터 타입을 말하며, 포트 번호를 처리할 때 사용한다. Little -> Big

- ntoa : Network to ASCII, Big-Endian으로 저장된 ip주소를 문자열로 읽기 좋게 해준다.

-> C0 0A A8 63 -> 192.10.168.99

- ntohl : htonl의 반대 개념이다. Big -> Little

- ntohs : htons의 반대 개념이다. Little -> Big


Dos : Denial of Service Attack( 서비스 거부 공격 )

DDoS : Distributed Dos( 분산 서비스 거부 공격 )

근데 일반적으로 최근 컴퓨터의 성능이 매우 향상되어 DDoS공격은 잘 먹히지 않는다


Protocol Family : 프로토콜 계열, 통신 규약( TCP, UDP, 등 여러 프로토콜이 존재한다. )

Address Family : 주소 계열( IP )

INET : Inter Network(인터넷)의 약자.


grep : Linux 명령어. 파일이나 폴더에서 해당 문자열을 검색한다.

/ : vi에서 문자열을 검색.


wine : 윈도우 프로그램을 리눅스에서 구동되게 하는 유틸리티.


신뢰성 : 파일의 100% 전송을 확신하는 것. Stream을 이용한다.

-> 받았는지 확인하여 안받았으면 다시 보내고, 받았으면 다음을 보낸다. TCP는 신뢰성 통신이다. IP는 TCP에 밀접되어 있어 보통 TCP는 IP와 붙여 TCP/IP라고 한다.

비신뢰성 : 파일이 100%전송되는 것을 보장하지 못한다. Data Gram을 이용한다.

-> 받건 안받건 다음 내용을 보낸다. UDP는 비신뢰성 통신이라고 한다.


랑데부 소켓 : 외부에서 클라이언트를 받아오는 소켓(주쌤 표현으로는 얼굴마담...)

커뮤니케이션 소켓 : 내부에서 클라이언트의 데이터를 처리하는 소켓


서버의 동작 과정

 번호

이름

설명 

소켓 생성

socket 함수를 이용해 server socket을 생성하고 연다.

2

구조체 설정

소켓에 대한 정보들을 입력한다.

3

바인딩

구조체를 소켓에 적용시킨다.

4

Listen 

접속 전에 대기, 2번째 인자는 대기 최대 인원이다.(매우 빠르므로 거의 의미가 없음) 

//함수 원형 설명 추가하기

5

Accept 

접속을 수락한다 


TCP는 3 Handshake 방식으로 접속한다. 단 이 방법은 도중에 무언가 사라지면 작업에 장애를 초래할 수 있다. 이 허점을 파고들어 공격하는 것이 DDoS이다.


접속하는 방법 : VMware에서 서버를 가동한 상태에서 윈도우의 명령프롬프트를 열고 텔넷으로 리눅스에서 설정한 ip와 소스에서 설정한 포트를 입력하여(telnet xxx.xxx.xxx.xxx 9999) 접속한다.


서버 소스(server.c)

#include <stdio.h>
#include <sys/socket.h>  // 소켓 함수용 라이브러리.
#include <arpa/inet.h>
#include <stdlib.h>  // C 표준 라이브러리.
#include <string.h>
#include <unistd.h>

#define  MAXPENDING  5  // 최대 허용 대기 가능 인원

int main()
{
  int servSock;  // 서버 소켓번호는 정수형으로 이루어져 있다.
  int clntSock;  // 클라이언트 소켓.
  struct sockaddr_in echoServAddr;  //  서버 소켓 구조체(신버전)
  struct sockaddr_in echoClntAddr;  //  클라이언트 주소...
  unsigned short echoServPort;  // 서버 포트.... 9999...
  unsigned int clntLen;  // 

  int iRet;  // 잡동사니를 넣어두는 변수.

  unsigned char ucBuffer[500];  // 클라이이언트로부터 메시지를 저장하는 버퍼.
  

  echoServPort = 9999;  // 사용할 포트 번호.

  servSock = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );  // Socket을 생성한다.
  // Protocol Family

  if( servSock < 0 )  // 위의 구문에서 에러가 발생했다면
  {
    printf( "Socket Function Error!\n" );
    return0 );
  }

  memset( &echoServAddr, 0sizeof( echoServAddr ) );  //해당 메모리를 전부 0으로 초기화.
  echoServAddr.sin_family = PF_INET;  // Internet Address Family
  echoServAddr.sin_addr.s_addr = htonl( INADDR_ANY );  // INADDR_ANY는 자동으로 주소를 입력시켜 준다. 직접 입력해도 되나, 메모리에 저장되는 방식에 유의해야 한다.(Little->Big(표준))
  // 서버 주소는 반드시 고정되어야 하지만 클라이언트에서는 클라이언트의 주소를 자동할당하는 것이 좋다. 컴퓨터가 바뀌어도 자동 할당됨.
  echoServAddr.sin_port = htons( echoServPort );  // 포트 번호도 Big-Endian으로 바꿔주어야 한다. short형이므로 htons
  
  iRet = bind( servSock, ( struct sockaddr * )&echoServAddr, sizeof( echoServAddr ) );
  // 열려 있는 소켓에 포트 번호, IP등을 부여한다. 바인딩
  // bind함수에 쓰이는 인자는 구형 구조체이므로 캐스팅한다.
  // 블로킹 함수가 아니다.
  
  if( iRet < 0 )  // 위의 구문에서 에러가 발생했다면
  {
    close( servSock );  // 소켓을 연 이후 에러가 났으므로 닫아주도록 한다.
    printf( "Bind Failed Error!\n" );
    return0 );
  }

  iRet = listen( servSock, MAXPENDING ); // MAX PENDING : 5

  if( iRet < 0 )  // 위의 구문에서 에러가 발생했다면...
  {  
    close( servSock );  // 소켓을 연 이후 에러가 났으므로 닫아주도록 한다.
    printf( "Listen  Failed Error!\n" );
    return0 );
  }


  clntLen = sizeof( echoClntAddr );
  clntSock = accept( servSock, ( struct sockaddr * )&echoClntAddr, &clntLen );
  // 들어오는 사람의 IP 및 정보가 요구되므로 2번째 인자가 클라이언트 정보.
  // accept는 구 자료형 형식의 함수이기 때문에 강제 캐스팅
  // clntLen : 크기.
  // accept에서는 접속이 될 때 까지 그대로 대기상태가 된다. 블로킹 함수.
  // servSock : 랑데부 소켓(외부에서 받아들이기만 한다)
  // clntSock : 커뮤니케이션 소켓. 내용을 처리할 때 쓰인다.
  
  if( clntSock < 0 )
  {
    close( servSock );  // 서버 소켓은 열려 있으므로 닫아준다.
    printf( "Accept Function Error!\n" );
    return0 );
  }
    
  printf( "Handling client IP : %s\n", inet_ntoa( echoClntAddr.sin_addr ) );
  // Network to ASCII Code(수치로만 되어있는 IP주소를 사용자가 알아볼 수 있게 문자열로 바꾸어준다.)
  
  printf( "Handling client PORT : %d\n", ntohs( echoClntAddr.sin_port ) );
  // Big-Endian으로 저장된 클라이언트의 포트 정보를 서버에 맞게 Little-Endian으로 변환하여 출력한다.
  
  while1 )
  {
    iRet = read( clntSock, ucBuffer, sizeof( clntSock ) );
    // 커뮤니케이션 소켓으로부터 값을 읽어온다.
    // read함수는 글자 수를 반환하므로 iRet에 글자수를 임시로 저장한다.
    ucBuffer[ iRet ] = 0;  // 마지막 글자는 \n(개행문자)이므로 NULL로 처리한다.
    write( 1, ucBuffer, iRet );  // 버퍼에 있는 내용을 stdout(화면)에 출력한다.

    if'q' == ucBuffer[0] )  // 첫 글자가 'q'이면 서버 프로그램을 종료한다.
    {
      break;
    }
  }

  close( servSock );  // 서버 소켓을 종료한다.
  close( clntSock );  // 클라이언트 소켓을 종료한다.
  
  return0 );  // 빠빠이
}


'Programming > TCP IP' 카테고리의 다른 글

[TCP/IP] 130613목 - 기본 IP설정, 소켓 개념(덜씀..)  (3) 2013.06.13

+ Recent posts