교육/Network

네트워크프로그래밍 6/7

솔♡ 2014. 6. 23. 09:39








헤더 데이터

데이터가있으면 헤더가 있는데 그 공간에 ACK와 SYN, SEQ가 존재한다.

SEQ는 처음에 무슨값이 되든 상관없음.
시퀀스번호는 처음에 랜덤으로 지정해준다. 다른곳에서 같이 통신하면 혼선이 올 수 있기 때문에


SEQ 번호 (내꺼) ACK 번호 (받은거)












프로그램을 실행하기 위해서는 메모리로 들어가야 한다.
메모리가 좋을 수록 실행속도가 빨라진다.

프로세스 ID = PID
메모장을 두개 띄웠을 때도 프로세스의 번호는 다르다.































   시그널 핸들러    의미
   함수 이름     시그널을 받으면 '함수 이름' 함수가 실행된다.
   SIG_IGN    시그널을 받으면 무시한다.
   SIG_DFL    시그널을 받으면 시스템에서 기본적으로 설정한 동작을 한다.


void (*signal(int signum, void (*handler)(int)))(int);
(시그널
     ㄴ시그넘,핸들러(함수포인터)(핸들러의 인자 int))) (int);
         

-void(*)(int);
 = 핸들러의 기본형과 같다. 

smart / fp를 리턴 하면

void test(int); //함수 선언
void(*fp)(int); //변수(fp) 선언


smart(int,void (*)(int));
인자 1[int] = signum
인자 2[void (*)(int)] = handler

= void(*smart(int , void(*)(int)))(int);

(소프트웨어 인터럽트)
Win          Message
Java         Event
Linux        Signal



      1 #include <stdio.h>
      2 #include <signal.h>
      3 #include <unistd.h>
      4
      5 void signalHandler(int signo);
      6
      1 #include <stdio.h>
      2 #include <signal.h>
      3 #include <unistd.h>
      4
      5 void signalHandler(int signo);
      6
      7 int main()
      8 {
      9     /* SIGINT 시그널을 받으면 signalHandler 실행하도록 설정 */
     10     signal(SIGINT, signalHandler);
     11     //첫번째 인자에 있는 신호를 주면 signalHandler를 호출한다.
     12     //SIGINT = 인터럽트 키인 Ctrl-C를 눌렀을 때 발생하며 프로세스는 종료
     13     //소프트웨어 인터럽트라고한다.
     14
     15
     16     while(1)
     17     {
     18         printf("Hello World\n");
     19         sleep(1);
     20     }
     21
     22
     23     return 0;
     24 }
     25
     26 void signalHandler(int signo)
     27 {
     28     printf("Hi! signal %d \n",signo); /* signo는 시그널 번호 */
     29     /* SIGINT 시그널을 받으면 시스템에서 기본적으로 설정한 동작을 하도록
     30 //  signal(SIGINT, SIG_DFL); -> 주석처리하면 Ctrl-C를 눌렀을때 종료되지않고 Hi! signal만 출력됨
     31     //SIG_DFL = 시그널을 받으면 시스템에서 기본적으로 설정한 동작을 한다
     32 }



->이럴경우 ps-a한뒤 kill로 죽일 수 있다.


옵션 의미
SA_NOCLDSTOP signum이 SIGCHLD일 경우, 자식 프로세스가 멈추었을 때 부모 프로세스로 SIGCHLD가 전달되지 않는다.
SA_ONESHOT 또는
SA_RESETHAND
시그널을 받으면 설정된 행동을 취하고, 시스템 기본 설정인 SIG_DFL로 재설정 한다.
SA_RESTART 시그널 처리에 의해 방해받은 시스템 호출은 시그널 처리가 끝나면 재시작한다.
SA_NOMASK 또는
SA_NODEFER
시그널을 처리하는 동안에 전달되는 시그널은 블록화 되지 않는다.
SA_SLGINFO 이 옵션을 설정하지 않으면 시그널 번호만을 인수로 하는 sa_handler가 동작하며, 설정하면 세 개를 인수로 하는
sa_sigaction이 동작한다. 세 개의 인수는 시그널 번호, 시그널이 만들어진 이유, 시그널을 받는 프로세스의 정보다.



-다른 컴퓨터에서 같은 포트로 접속하여 server로 보낸 메시지-



------- 787p_28_1 -------


#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define PORT 4020    /* PORT 번호 */
#define MAXPENDING 5 /* 클라이언트 요구가 대기하는 큐의 크기 */
#define BUFSIZE 1024 /* recvBuffer의 크기 */

int main()
{
  int servSockfd;
  int clntSockfd;
  struct sockaddr_in servAddr;
  struct sockaddr_in clntAddr;
  char recvBuffer[BUFSIZE];
  int clntLen;
  int recvLen;
  pid_t processID;

  /* 소켓 생성 */
  if((servSockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  {
    perror("sock failed");
    exit(1);
  }

  /* servAddr을 0으로 초기화 */
  memset(&servAddr, 0sizeof(servAddr));
  /* servAddr에 IP 주소와 포트 번호를 저장 */
  servAddr.sin_family = AF_INET;
  servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servAddr.sin_port = htons(PORT);

  /* servSockfd 소켓에 주소 정보 연결 */
  if(bind(servSockfd, (struct sockaddr *)&servAddr, sizeof(servAddr)) == -1)
  {
    perror("bind failed");
    exit(1);
  }

  /* servSockfd으로 들어오는 클라이언트 요청 기다림 */
  if(listen(servSockfd, MAXPENDING) == -1)
  {
    perror("listen failed");
    exit(1);
  }

  /* 무한 반복 */
  while(1)
  {
    clntLen = sizeof(clntAddr);
    /* 요청을 받아들이고 새로운 clntSockfd 소켓이 클라이언트와 연결 */
    if((clntSockfd = accept(servSockfd, (struct sockaddr *)&clntAddr, &clntLen)) == -1)
    {
      perror("accept failed");
      exit(1);
    }

    /* 자식 프로세스 생성 */
    if((processID = fork()) == -1)
    {
      perror("fork failed");
      exit(1);
    }
    else if(processID == 0)
    {
      close(servSockfd);
      /* 임의의 클라이언트에 대해 반복 */
      while(1)
      {
        /*clntSockfd 소켓으로 들어오는 데이터를 받아 recvBuffer에 저장 */
        if((recvLen = recv(clntSockfd, recvBuffer, BUFSIZE, 0)) == -1)
        {
          perror("recv failed");
          exit(1);
        }

        /* 클라이언트가 연결을 끊으면 recv는 0을 반환 */
        if(recvLen == 0)
        {
          break;
        }

        recvBuffer[recvLen] = 0;
        /* 받은 데이터를 출력 */
        printf("Received : %s \n", recvBuffer);

        /* 받은 데이터를 클라이언트에게 보냄 */
        if(send(clntSockfd, recvBuffer, recvLen, 0) != recvLen)
        {
          perror("send failed");
          exit(1);
        }
      }
      /* clntSockfd 소켓 닫음 */
      close(clntSockfd);
      /* 자식 프로세스 종료 */
      exit(0);
    }

    /* 부모 프로세스는 clntSockfd 소켓을 닫고 while 문 시작 부분으로 이동 */
    close(clntSockfd);
  }
}





------client_2-------




#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define PORT 4020
#define BUFSIZE 1024


int main(int argc, char *argv[])
{
  int sockfd;
  struct sockaddr_in servAddr;
  char sendBuffer[BUFSIZE], recvBuffer[BUFSIZE];
  int recvLen;

  if(argc != 2)
  {
    fprintf(stderr, "Usage : %s IP_address \n", argv[0]);
    exit(1);
  }

  if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  {
    perror("sock failed");
    exit(1);
  }

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

  servAddr.sin_family = AF_INET;
  servAddr.sin_addr.s_addr = inet_addr(argv[1]);
  servAddr.sin_port = htons(PORT);

  if(connect(sockfd, (struct sockaddr*)&servAddr, sizeof(servAddr)) == -1
  {
    perror("connect failed");
    exit(1);
  }

  while(1)
  {
    printf("Input sending message ==> ");
    fgets(sendBuffer, BUFSIZE, stdin);
    
    if(!strncmp(sendBuffer, "quit"4))
    {
      break;
    }

    if(send(sockfd,sendBuffer,strlen(sendBuffer), 0) != strlen(sendBuffer))
    {
      perror("send failed");
      exit(1);
    }

    if((recvLen = recv(sockfd, recvBuffer, BUFSIZE-10)) <= 0)
    {
      perror("recv failed");
      exit(1);
    }

    recvBuffer[recvLen] = '\0';

    printf("Received : %s \n", recvBuffer);
  }

  close(sockfd);
  
  exit(0);
}






------
 
  P                               P'

Code       ->      Code영역은 복사하지않고 그대로 쓴다.
Data
BSS
Hip        ->
Steck      ->

thread
쓰레드를 100개 만들어 놓으면 부모가 죽을때 싹다 죽음.
fork로 만들면 부모가 죽어도 99개의 자식프로세스가 살아있다.

ㄴ C언어와는 다른 개념이다.


Posix규약

POSIX[포직스]는 유닉스 운영체계에 기반을 두고 있는 일련의 표준 운영체계 인터페이스이다. 표준화에 관한 필요성은, 컴퓨터를 사용하고 있는 기업들이 다시 코딩하지 않고서도 다른 컴퓨터 회사가 만든 컴퓨터 시스템에도 운영할 수 있도록, 호환성이 있는 프로그램을 개발하기 원하는 데에서 기인했다. 유닉스는 제작자와 비교적 무관한, 중립적인 입장에 있었기 때문에 표준 시스템 인터페이스로 선정되었다. 그러나, 몇몇 주요 유닉스 버전들은 공통 분모에 해당하는 시스템을 개발해야할 필요가 상존하고 있었다.

비공식적으로, POSIX 내의 각 표준은 POSIX라는 용어 다음에 소수로 표시하도록 정의되었다. 그래서, POSIX.1은 C 언어 응용프로그램 인터페이스의 표준이다. POSIX.2는 표준 쉘과 유틸리티 인터페이스이다 (즉, 사용자가 운영체계와 명령어로 인터페이스 하는 것). 스레드 관리용 POSIX.4를 포함한 두 개의 주요 인터페이스가 추가적으로 개발되거나 개발 중에 있다. POSIX 인터페이스들은 IEEE의 후원 하에 개발되었다.

최근에, POSIX.1과 POSIX.2 인터페이스들은 X/Open 프로그래밍 가이드 4.2 (이는 "단일 유닉스 규격" 또는 "유닉스 95"라고도 불린다)라고 불리는 다소 커다란 인터페이스 내에 포함되었다. 유닉스의 상표는 산업계 표준화 그룹인 오픈그룹이 가지고 있으며, "유닉스"시스템으로서의 인터페이스에 부합하는 운영체계에 상표권을 부여할 권리를 가지고 있다. IBM의 OS/390은 유닉스 인터페이스 상표를 가지고 있는 운영체계의 일례이다.


-man pthread_create-

       #include <pthread.h> // 사용할 헤더파일

       int  pthread_create(pthread_t  *  thread, pthread_attr_t *attr, void * (*start_routine)(void *), void * arg);
       -반드시 인자를 void포인터로 받고 void포인터를 return하는 함수를 3번째에 넣어라.
       -void와 void포인터는 전혀다른개념이다. //인자를 아무 자료형이나 다 넣을 수 있도록.. void 포인터형으로 선언
       -함수를 유연하게 처리할 수 있도록 했음.


-man 3 sleep-

       #include <unistd.h>

       unsigned int sleep(unsigned int seconds);

       sleep()은  현재  동작  중인  프로세스를  seconds  초시간이
       경과하거나 무시할 수 없는 시그널이 올 때까지 정지시킨다.


 gcc -o pthread_create pthread_create.c -lpthread
-l 은 라이브러리의 약자

"pts/35" - 원하는 포트번호를 보게함

ps -a/greap -"pts/35" - 35번 포트의 작업과정을 볼 수 있다.

 ps --User ID(리눅스 아이디)
- 적은 ID의 작업과정을 볼 수 있다.


레이스컨디션 -
같은 자원을 두고 두개이상의 함수가 데이터를 쓰고있는 경우.(여러개의 함수가 같은 전역변수를 씀)
-해킹당할 위험이 높기에 전역변수를 쓰는것을 권장하지 않고 지역변수를 쓰는것을 권장한다.-
/경쟁상태를 이용하여 관리자 권한을 획득하려는 시도/

-ex소스-

      1 #include <stdio.h>
      2 #include <pthread.h>
      3 #include <unistd.h>
      4 //sleep을 사용하기 위한 헤더파일
      5
      6 void * smart1(void *);
      7 void * smart2(void *);
      8 void * smart3(void *);
      9
     10 volatile unsigned int uiCnt;
     11 //전역변수 하나에 함수 3개가 사용하고 있다. smart1,2,3
     12 //레이스 컨디션이라고 한다.
     13 //한정된 자원을 동시에 사용하려는 여러개의 프로세스가 자원 위해 경쟁을 >
     14 //보통 SETUID가 걸려있는 파일을 일반 계정으로 공격을 한다.
     15 //서로 데이터를 차지하려 함.
     16
     17
     18
     19 int main()
     20 {
     21     pthread_t thread1;
     22     pthread_t thread2;
     23     pthread_t thread3;
     24
     25     pthread_create(&thread1, 0, smart1,0);
     26     pthread_create(&thread1, 0, smart2,0);
     27     pthread_create(&thread1, 0, smart3,0);
     28
     29     getchar();
     30 //  동작을 멈추기 위해서
     31
     32     return 0;
     33 }
     34
     35 void * smart1(void * vpData)
     36 //2번째 인자는 일반적으로 0을 넣음
     37 {
     38     while(1)
     39     {
     40         printf("1 : [%u]\n", uiCnt);
     41         sleep(1);
     42
     43         ++uiCnt;
     44     }
     45 }
     46
     47 void * smart2(void * vpData)
     48 {
     49     while(1)
     50     {
     51         printf("2 : [%u]\n",uiCnt);
     52         sleep(1);
     53
     54         ++uiCnt;
     55     }
     56 }
     57
     58 void * smart3(void * vpData)
     59 {
     60     while(1)
     61     {
     62         printf("3 : [%u]\n",uiCnt);
     63         sleep(1);
     64
     65         ++uiCnt;
     66     }
     67 }
     68
     69