Busan IT/공장내 Network2015. 8. 27. 17:23

==================================Outline====================================

Select 함수를 사용한 채팅프로그램

- 초과 접속자 발생 시 차단

- ctrl + d 입력 시 정상종료

- 포트 설정

- ctrl + c 정상종료

----------------------------------------------------------------------------

초과 접속자 발생 시 차단

 

지난 시간에 이어...

 

접속자 제한을 3으로 하자. 서버에 접속자가 초과 된 상황을 만들기 위한 작업이다.

 

** 코딩내용을 수정할 때 우선 코딩의 전체 흐름을 살펴본다.

수정한 코드가 전체 프로그램에 미치는 영향을 파악한 후 작업을 진행해야 한다.

눈에 실핏줄 터지기 싫으면...

 

smartsock.h에서 MAX_USER 값을 30에서 3으로 줄인다.

 

 

접속 제한 숫자를 초과하는 클라이언트의 접속을 막아야 한다. 하지만 영문도 모르고 접속이 안되는 접속자의 속상함 방지를 위해, 일단 접속은 허가한 후 넌 팅길거라는 메시지를 보내준다. 초과 접속작의 접속 처리를 위해 접속자의 대화 소켓을 담는 icSock변수를 icSock[MAX_USER+1]로 처리해준다.

 

 

 

accept후 조건문을 만들어 uiUser의 크기가 MAX_USER가 크거나 같을 때 사용자의 접속을 끊고 안내 메시지(꺼져)를 보내준다.

 

 

컴파일 후 클라이언트를 접속시키면 서버와 제한 숫자 내 클라이언트는 정상 작동하지만, 초과 접속한 클라이언트에게 무한반복으로 버퍼에 있는 메시지가 출력된다. 초과인원이 출입 시 동작하는 if문으로 간다. 초과 접속된 클라이언트에게 종료 메시지를 보내주고 클라이언트에서는 해당 메시지를 받으면 접속이 끊어지도록 코딩하자.

 

 

<server.c>

 

  

 

<client.c>

 

** 캡쳐된 코드 소속이 궁금할 때 구분법: iFd쓰면 client, icSock/iSock쓰면 server

 

 

ctrl + d 입력 시 정상종료

 

서버에서 Ctrl + D를 누르면 모든 클라이언트에게 종료 메시지를 출력하고 서버를 종료하도록 처리해주자.

 

 

 

<client.c>

 

 

 

포트 설정

 

PORT를 세련되게 고쳐 주자.

우선 실행파일이 인자를 받을 수 있도록 메인함수를 고쳐준다. 서버부터.

 

 

실행 시 포트번호를 인자로 받게 되고 이것이 유효한 숫자일 경우 포트번호를 변경해준다.

 

 

 

bind를 위해 접속정보를 세팅하는 구조체로 가서 PORT번호를 수정해준다.

 

 

클라이언트에서도 똑같이 작업해준다.

 

 

 

ctrl + c 정상종료

 

서버나 클라이언트에서 정상종료가 아닌 ctrl+c를 눌렀을 경우에도 클라이언트가 고통 받지 않고 정상종료 하도록 코딩해주자.

 

ctrl+c로 눌렀을 경우, 대화소켓으로 받은 read의 반환 값은 0이 된다. 이를 활용하여 read값이 0일 경우 정상종료 시켜주자.

 

<server.c>

 

 

 

<client.c>

 

 

채팅 서버, 클라이언트 만들기는 여기서 끝낸다. 지금까지 코딩한 채팅 프로그램이 성에 안차면 멀티룸 채팅에 도전해 보시씨요.

 

** 멀티룸 채팅 : 채팅 방을 여러 개 만들어서 유저가 선택적으로 접속


/*** 소스 ***/


#include "smartsock.h"

int main(int iRtn, char *cpCMD[])
{
  int iFd;
  struct sockaddr_in stAddr;
  int iLen;
  char cBuf[BUF_SIZE];  
  fd_set fdRead;
  char cMSG[MSG_SIZE];
  char cNick[NIC_NAME_SIZE];
  unsigned short usPORT=PORT; //PORT == 7777

  if(iRtn == 2)
  {
    iFd  = atoi(cpCMD[1]);
    if(1024 < iFd)
    {
      if(65535 > iFd)
      {
        usPORT=iFd;        
        printf("PORT no. %d\n", usPORT);
      }
    }
  }


  /*** Nick Name in ***/
  while(1)
  {
    printf("Please Input Nick Name\n");
    fflush(stdout);
    iRtn = read(0, cNick, NIC_NAME_SIZE);
    if(iRtn < 2)//그냥 엔터키를 눌렀을 경우. **ctl + d 누르면 iRtn = 0
      continue;

    cNick[iRtn-1= 0;
    break;

  }
  /*** socket ***/

  iFd = socket(AF_INET, SOCK_STREAM, 0);
  if(-1 == iFd)
  {
    perror("socket:");
    return 100;
  }

  /*** structure setting ***/
  stAddr.sin_family = AF_INET;
  stAddr.sin_addr.s_addr = inet_addr(IP);
  stAddr.sin_port = htons(usPORT);

  iLen = sizeof(struct sockaddr_in);

  /*** connect ***/
  iRtn = connect(iFd, (struct sockaddr *)&stAddr, iLen);
  if(-1 == iRtn)
  {
    perror("connect:");
    close(iFd);
    return 200;
  }

  write(iFd, cNick, NIC_NAME_SIZE);

  while(1)
  {
    FD_ZERO(&fdRead);  
    FD_SET(0&fdRead);
    FD_SET(iFd, &fdRead);      
    select(iFd+1,&fdRead, 000);

    if(0 != (FD_ISSET(0&fdRead) ) )
    {
      iRtn = read(0, cBuf, BUF_SIZE);      
      if(iRtn == 0)
      {
        write(iFd, MSG_END, sizeof(MSG_END));
        break;
      }
      cBuf[iRtn - 1= 0;
      sprintf(cMSG, "[%s]%s ", cNick, cBuf);
      write(iFd, cMSG, MSG_SIZE);

      printf("[Send MSG]: [%s]\n", cBuf);    
    }
    if(0 != (FD_ISSET(iFd, &fdRead) ))
    {
      iRtn = read(iFd, cMSG, sizeof(cMSG));      
      if(iRtn == 0)
      {
        printf("Server does not respond\n");
        break;
      }
      if0 == strncmp(cMSG, MSG_END, sizeof(MSG_END) ))
      {
        break;

      }
      printf("[%s]\n", cMSG);    
    }
  }



  /*** read & write ***/
  //memset(cBuf, 0, BUF_SIZE);
  //iRtn = read(0, cBuf, BUF_SIZE);

  close(iFd);
  return 0;
}

<client.c>


#include "smartsock.h"
#include <unistd.h>

int main(int iRtn, char *cpCMD[])
{
  int iSock;   //소켓 함수의 반환 값을 받는 변수
  int icSock[MAX_USER+1];   //accept의 반환 값을 받는 변수
  struct sockaddr_in stAddr;
  socklen_t uiSockLen=sizeof(struct sockaddr);
  char cBuf[BUF_SIZE];
  const char * cP;
  fd_set fdRead;
  unsigned int uiUser;
  unsigned int uiCnt, uiCnt2;
  int iMSock;  //store greatest number in file descriptors
  char cNick[MAX_USER][NIC_NAME_SIZE];
  char cMSG[MSG_SIZE];
  unsigned short usPORT=PORT;  //PORT == 7777

  if(iRtn == 2)
  {
    iSock  = atoi(cpCMD[1]);
    if(1024 < iSock)
    {
      if(65535 > iSock)
      {
        usPORT = iSock;
        printf("PORT no. %d\n", usPORT);
      }
    }
  }

  iSock = socket(AF_INET, SOCK_STREAM, 0);    //AF_INET = 2, 
  if(0 > iSock)
  {
    perror("socket : ");
    return -1;
  }
  // stAddr구조체에 socket연결을 위한 필수 정보 입력  setting
  bzero(&stAddr, sizeof(stAddr));            //구조체 비우기(0으로 채우기)
  stAddr.sin_family = AF_INET;               //#define AF_INET 2 /* IP protocol family. */
  stAddr.sin_addr.s_addr = inet_addr(IP);    //IP와 PORT값은 헤더파일에 정의되어 있다.
  stAddr.sin_port = htons(usPORT);

  iRtn = bind(iSock, (struct sockaddr *)&stAddr,sizeof(stAddr));
  if(iRtn < 0)
  {
    perror("bind : ");
    close(iSock);

    return -2;
  }
  iRtn = listen(iSock, 5);
  if(iRtn != 0)
  {
    perror("listen : ");
    close(iSock);

    return -3;
  }
  uiUser = 0;
  while(1
  {
    // setting fd_set
    FD_ZERO(&fdRead);
    FD_SET(0&fdRead);
    FD_SET(iSock, &fdRead);
    iMSock = iSock;    

    for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)  //사용자가 접속하면 해당 Fd를 set해주고 가장 높은 fd값을 저장
    {
      FD_SET(icSock[uiCnt], &fdRead);
      //FD_SET(iSock, &fdRead);
      if(iMSock < icSock[uiCnt])
      {
        iMSock = icSock[uiCnt];
      }      
    }
    select((iMSock+1), &fdRead, 000);//select 함수를 사용하여 감시해준다.(입력이 있을때까지 무한대기)
    if0 != FD_ISSET(iSock, &fdRead) ) //지정된 소켓 번호가 있으면 대화 소켓 번호를 받아저장하고 user+
    {
      icSock[uiUser] = accept(iSock, (struct sockaddr *)&stAddr, &uiSockLen); //접속자의 정보가 stAddr에 입력된다.
      if(icSock[uiUser] < 0)
      {
        perror("Accept : ");
        continue;
      }
      if(uiUser >= MAX_USER)
      {
        read(icSock[uiUser], cBuf, sizeof(cBuf));
        sprintf(cMSG, "Server is not vacant");
        write(icSock[uiUser], cMSG, sizeof(cMSG));
        write(icSock[uiUser], MSG_END, sizeof(MSG_END));
        close(icSock[uiUser]);

        printf("Server is not vacant [%s]\n", cBuf);
        printf("Client iP :%s\n", inet_ntoa(stAddr.sin_addr));
        continue;
      }
      read(icSock[uiUser], cNick[uiUser], NIC_NAME_SIZE);
      printf("Incoming Client :[%s] \n", cNick[uiUser]);
      printf("Client IP :%s\n", inet_ntoa(stAddr.sin_addr));
      write(icSock[uiUser], "Welcome :)"sizeof("Welcome :)"));
      sprintf(cMSG, "[%s]님이 입장하셨습니다.",cNick[uiUser] );
      for(uiCnt2 = 0; uiCnt2 < uiUser; ++uiCnt2)
      {
        write(icSock[uiCnt2] ,cMSG, MSG_SIZE);
      }
      ++uiUser;

    }
    if(0 != FD_ISSET(0&fdRead))    //서버에서 키보드 입력 받은 내용 클라이언트에게 보내기
    {
      iRtn = read(0, cBuf, BUF_SIZE);
      if(iRtn == 0)
      {
        for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)
        {
          sprintf(cMSG, "Server is aborted");
          write(icSock[uiCnt], cMSG, sizeof(cMSG));
          write(icSock[uiCnt], MSG_END, sizeof(MSG_END));
        }
        break;
      }
      sprintf(cMSG, "[공지사항]:[%s]", cBuf);
      for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)
      {
        write(icSock[uiCnt], cMSG, MSG_SIZE);//모든 사용자에게 보낸다.
      }
    }
    for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)
    {  
      if0 != FD_ISSET(icSock[uiCnt], &fdRead))
      {
        iRtn = read(icSock[uiCnt], cMSG, MSG_SIZE);
        
        if(
        ( 0 == strncmp(cMSG, MSG_END, sizeof(MSG_END) )) 
        ||
        0 == iRtn)
        {
          sprintf(cMSG, "[%s]님이 퇴장하셨습니다.", cNick[uiCnt]);
          close(icSock[uiCnt]);
          --uiUser;
          icSock[uiCnt] = icSock[uiUser];          
          memcpy(cNick[uiCnt], cNick[uiUser], sizeof(NIC_NAME_SIZE));  
        }
        for(uiCnt2 = 0; uiCnt2 < uiUser; ++uiCnt2)
        {
          write(icSock[uiCnt2] ,cMSG, MSG_SIZE);
        }
      }
    }

  }
  for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)
  {
    close(icSock[uiCnt]);  
  }
  close(iSock);
  return 0;
}


<server.c>


#ifndef __SMARTSOCK_H__
#include <sys/select.h>
#define __SMARTSOCK_H__

#include <stdio.h>
#include <string.h>
#include <strings.h>
// socket & bind & listen & accept & connect
#include <sys/types.h>
#include <sys/socket.h>

// sockaddr_in
#include <netinet/in.h>

// read & write
#include <unistd.h>

// htonl
#include <arpa/inet.h>

// errno, perror
#include <errno.h>

// open
#include <fcntl.h>
#include <sys/stat.h>

//select
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>

#define PORT      7777
#define IP        "192.168.0.173"

#define MAX_USER     3
#define NIC_NAME_SIZE   9
#define NIC_NAME_MSG   (9+2)

#define BUF_SIZE  255              //only message
#define MSG_SIZE  (BUF_SIZE+1+NIC_NAME_MSG)  //message + Nick Name
#define MSG_END    "\x01\x02\x03"        



#endif /* __SMARTSOCK_H__ */


<smartsock.h>


/*** 파일 ***/

client.c


server.c


smartsock.h







반응형
Posted by newind2000
Busan IT/공장내 Network2015. 8. 26. 17:49

client2개 이상 서버에 접속하였을 경우, 한 쪽에서만 quit를 눌러도 접속한 클라이언트 모두가 서버에 접속이 끊기는 현상이 발생하였다. 이것을 막기 위해 ‘quit'가 키보드로부터 입력되었을 경우 이것을 종료시키는 명령을 키보드 입력을 감시하는 코드에 넣어주면 해결 된다.

 

 

현재 서버에 2개 이상의 클라이언트를 접속한 후에 강제 종료를 시키면 이전 메시지가 무한반복으로 경우가 발생한다. 이것을 해결해보자.

 

linux 압축

 

tar : 파일을 하나로 묶음

gzip : 용량을 압축

 

tar -xzvf : 압축 해제

 

 

클라이언트의 대화명을 설정할 수 있도록 해준 후 채팅을 할 수 있도록 만들어보자.

 

서버 - 클라이언트 관계에서 일반적으로 서버의 과부하를 줄이기 위해서 클라이언트에서 연산을 하도록 프로그램을 만들어 놓는다.

 

 

찾고자하는 단어 위에서 ‘*’을 누르면 해당 단어들이 노란색 배경으로 바뀐다.

 

 


/*** client.c ***/


#include "smartsock.h"

int main(void)
{
  int iFd;
  struct sockaddr_in stAddr;
  int iLen;
  int iRtn;
  char cBuf[BUF_SIZE];  
  fd_set fdRead;
  char cMSG[MSG_SIZE];
  char cNick[NIC_NAME_SIZE];
  
  /*** Nick Name in ***/
  while(1)
  {
    printf("Please Input Nick Name");
    fflush(stdout);
    iRtn = read(0, cNick, NIC_NAME_SIZE);
    if(iRtn < 2)//그냥 엔터키를 눌렀을 경우. **ctl + d 누르면 iRtn = 0
      continue;

    cNick[iRtn-1= 0;
    break;

  }
  /*** socket ***/

  iFd = socket(AF_INET, SOCK_STREAM, 0);
  if(-1 == iFd)
  {
    perror("socket:");
    return 100;
  }

  /*** structure setting ***/
  stAddr.sin_family = AF_INET;
  stAddr.sin_addr.s_addr = inet_addr(IP);
  stAddr.sin_port = htons(PORT);

  iLen = sizeof(struct sockaddr_in);

  /*** connect ***/
  iRtn = connect(iFd, (struct sockaddr *)&stAddr, iLen);
  if(-1 == iRtn)
  {
    perror("connect:");
    close(iFd);
    return 200;
  }

  write(iFd, cNick, NIC_NAME_SIZE);

  while(1)
  {
    FD_ZERO(&fdRead);  
    FD_SET(0&fdRead);
    FD_SET(iFd, &fdRead);      
    select(iFd+1,&fdRead, 000);

    if(0 != (FD_ISSET(0&fdRead) ) )
    {
      iRtn = read(0, cBuf, BUF_SIZE);      
      if(iRtn == 0)
      {
        break;
      }
      cBuf[iRtn - 1= 0;
      sprintf(cMSG, "[%s]%s ", cNick, cBuf);
      write(iFd, cMSG, MSG_SIZE);

      printf("[Send MSG]: [%s]\n", cBuf);    
    }
    if(0 != (FD_ISSET(iFd, &fdRead) ))
    {
      read(iFd, cMSG, MSG_SIZE);      
      printf("[%s]\n", cMSG);    
    }
  }



  /*** read & write ***/
  //memset(cBuf, 0, BUF_SIZE);
  //iRtn = read(0, cBuf, BUF_SIZE);

  write(iFd, MSG_END, sizeof(MSG_END));
  close(iFd);
  return 0;
}



/*** server.c ***/

#include "smartsock.h"
#include <unistd.h>

int main(void)
{
  int iSock;   //소켓 함수의 반환 값을 받는 변수
  int icSock[MAX_USER];   //accept의 반환 값을 받는 변수
  int iRtn;
  struct sockaddr_in stAddr;
  socklen_t uiSockLen=sizeof(struct sockaddr);
  char cBuf[BUF_SIZE];
  const char * cP;
  fd_set fdRead;
  unsigned int uiUser;
  unsigned int uiCnt, uiCnt2;
  int iMSock;  //store greatest number in file descriptors
  char cNick[MAX_USER][NIC_NAME_SIZE];
  char cMSG[MSG_SIZE];


  iSock = socket(AF_INET, SOCK_STREAM, 0);    //AF_INET = 2, 
  if(0 > iSock)
  {
    perror("socket : ");
    return -1;
  }
  // stAddr구조체에 socket연결을 위한 필수 정보 입력  setting
  bzero(&stAddr, sizeof(stAddr));            //구조체 비우기(0으로 채우기)
  stAddr.sin_family = AF_INET;               //#define AF_INET 2 /* IP protocol family. */
  stAddr.sin_addr.s_addr = inet_addr(IP);    //IP와 PORT값은 헤더파일에 정의되어 있다.
  stAddr.sin_port = htons((PORT));

  iRtn = bind(iSock, (struct sockaddr *)&stAddr,sizeof(stAddr));
  if(iRtn < 0)
  {
    perror("bind : ");
    close(iSock);

    return -2;
  }
  iRtn = listen(iSock, 5);
  if(iRtn != 0)
  {
    perror("listen : ");
    close(iSock);

    return -3;
  }
  uiUser = 0;
  while(1
  {
    // setting fd_set
    FD_ZERO(&fdRead);
    FD_SET(0&fdRead);
    FD_SET(iSock, &fdRead);
    iMSock = iSock;    

    for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)  //사용자가 접속하면 해당 Fd를 set해주고 가장 높은 fd값을 저장
    {
      FD_SET(icSock[uiCnt], &fdRead);
      //FD_SET(iSock, &fdRead);
      if(iMSock < icSock[uiCnt])
      {
        iMSock = icSock[uiCnt];
      }      
    }
    select((iMSock+1), &fdRead, 000);//select 함수를 사용하여 감시해준다.(입력이 있을때까지 무한대기)
    if0 != FD_ISSET(iSock, &fdRead) ) //지정된 소켓 번호가 있으면 대화 소켓 번호를 받아저장하고 user+
    {
      icSock[uiUser] = accept(iSock, (struct sockaddr *)&stAddr, &uiSockLen); //접속자의 정보가 stAddr에 입력된다.
      if(icSock[uiUser] < 0)
      {
        perror("Accept : ");
        continue;
      }
      read(icSock[uiUser], cNick[uiUser], NIC_NAME_SIZE);
      printf("Incoming Client :[%s] \n", cNick[uiUser]);
      printf("Client IP :%s\n", inet_ntoa(stAddr.sin_addr));
      write(icSock[uiUser], "Welcome :)"sizeof("Welcome :)"));
      sprintf(cMSG, "[%s]님이 입장하셨습니다.",cNick[uiUser] );
      for(uiCnt2 = 0; uiCnt2 < uiUser; ++uiCnt2)
      {
        write(icSock[uiCnt2] ,cMSG, MSG_SIZE);
      }
      ++uiUser;

    }
    if(0 != FD_ISSET(0&fdRead))    //서버에서 키보드 입력 받은 내용 클라이언트에게 보내기
    {
      iRtn = read(0, cBuf, BUF_SIZE);
      cBuf[iRtn - 1= 0;

      sprintf(cMSG, "[공지사항]:[%s]", cBuf);
      for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)
      {
        write(icSock[uiCnt], cMSG, MSG_SIZE);//모든 사용자에게 보낸다.
      }
    }
    for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)
    {  
      if0 != FD_ISSET(icSock[uiCnt], &fdRead))
      {
        read(icSock[uiCnt], cMSG, MSG_SIZE);
        if0 == strncmp(cMSG, MSG_END, sizeof(MSG_END) )) 
        {
          sprintf(cMSG, "[%s]님이 퇴장하셨습니다.", cNick[uiCnt]);
          close(icSock[uiCnt]);
          --uiUser;
          icSock[uiCnt] = icSock[uiUser];          
          memcpy(cNick[uiCnt], cNick[uiUser], sizeof(NIC_NAME_SIZE));  
        }
        for(uiCnt2 = 0; uiCnt2 < uiUser; ++uiCnt2)
        {
          write(icSock[uiCnt2] ,cMSG, MSG_SIZE);
        }
      }
    }

  }
  for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)
  {
    close(icSock[uiCnt]);  
  }
  close(iSock);
  return 0;
}


반응형
Posted by newind2000
Busan IT/공장내 Network2015. 8. 26. 10:09

==================================Outline====================================
Select함수를 사용한 채팅 서버
----------------------------------------------------------------------------



/*** server.c ***/

#include "smartsock.h"
#include <unistd.h>

int main(void)
 {
   int iSock;   //소켓 함수의 반환 값을 받는 변수
  int icSock[MAX_USER];   //accept의 반환 값을 받는 변수
  int iRtn;
   struct sockaddr_in stAddr;
   socklen_t uiSockLen=sizeof(struct sockaddr);
   char cBuf[BUF_SIZE];
   const char * cP;
   fd_set fdRead;
   unsigned int uiUser;
   unsigned int uiCnt, uiCnt2;
   int iMSock;  //store greatest number in file descriptors


   iSock = socket(AF_INET, SOCK_STREAM, 0);    //AF_INET = 2, 
   if(0 > iSock)
   {
     perror("socket : ");
     return -1;
   }
   // stAddr구조체에 socket연결을 위한 필수 정보 입력  setting
   bzero(&stAddr, sizeof(stAddr));            //구조체 비우기(0으로 채우기)
   stAddr.sin_family = AF_INET;               //#define AF_INET 2 /* IP protocol family. */
   stAddr.sin_addr.s_addr = inet_addr(IP);    //IP와 PORT값은 헤더파일에 정의되어 있다.
   stAddr.sin_port = htons((PORT));

   iRtn = bind(iSock, (struct sockaddr *)&stAddr,sizeof(stAddr));
   if(iRtn < 0)
   {
     perror("bind : ");
     close(iSock);

     return -2;
   }
   iRtn = listen(iSock, 5);
   if(iRtn != 0)
   {
     perror("listen : ");
     close(iSock);

     return -3;
   }
   uiUser = 0;
   while(1
   {
     // setting fd_set
     FD_ZERO(&fdRead);    //fdRead 변수 1024byte 전부 0으로 세팅 
     FD_SET(0&fdRead);  //키보드 입력 감시
     FD_SET(iSock, &fdRead);  //접속 소켓 감시
     iMSock = iSock;      //소켓의 최대값 저장 -> select함수 첫번째 인자는 감시하는 파일 값 + 1기 때문이 이에 대한 최대값 저장

     for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)  //사용자가 접속하면 해당 Fd를 set해주고 가장 높은 fd값을 저장
    {
       FD_SET(icSock[uiCnt], &fdRead);  //접속한 사용자수만큼의 icSock배열에 소켓 값이 들어있음으로 이를 감시 
       if(iMSock < icSock[uiCnt])
       {
         iMSock = icSock[uiCnt];  //iMSock에 소켓의 최대값 저장
       }      
     }

     select((iMSock+1), &fdRead, 000);//select 함수를 사용하여 감시해준다.(입력이 있을때까지 무한대기)

     if0 != FD_ISSET(iSock, &fdRead) ) //랑데뷰 소켓이 set(1)되어 있으면(사람이 접속하면) accept함수를 받아서 대화 소켓을 열어준다.
     {
       icSock[uiUser] = accept(iSock, (struct sockaddr *)&stAddr, &uiSockLen); //대화 소켓 값을 icSock배열에 저장해준다.
       if(icSock[uiUser] < 0)
       {
         perror("Accept : ");
         continue;
       }
       printf("Incoming Client \n");
       printf("Client IP :%s\n", inet_ntoa(stAddr.sin_addr));      //사용자가 접속하면 IP를 출력시켜준다.
       write(icSock[uiUser], "Welcome :)"sizeof("Welcome :)"));    //접속자에게 "Welcome" 메세지 전송
       ++uiUser;                //사용자 수 +
     }
     if(0 != FD_ISSET(0&fdRead))                //서버에서 입력 값이 있을 경우에
    {  
       iRtn = read(0, cBuf, MSG_SIZE);            //키보드 값을 읽어 cBuf에 저장
       cBuf[iRtn - 1= 0;              //\n\r을 제거하기 위해 문자열 끝에 0을 강제 삽입
       for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)
       {
         write(icSock[uiCnt], cBuf, MSG_SIZE);//모든 사용자에게 보낸다.    //접속한 클라이언트에게 메세지 전송
       }
     }
     for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)          //접속 클라이언트 대화 소켓을 순회하면서 대화내용이 있는지 확인
     {  
       if0 != FD_ISSET(icSock[uiCnt], &fdRead))
       {
         read(icSock[uiCnt], cBuf, MSG_SIZE);          //대화가 있으면 읽어들임
         for(uiCnt2 = 0; uiCnt2 < uiUser; ++uiCnt2)
         {
           if(uiCnt != uiUser)      
             write(icSock[uiCnt2] ,cBuf, MSG_SIZE);        //모든 클라이언트들에게 내용을 전송
         }
         if0 == strncmp(cBuf,MSG_END, strlen(MSG_END)) )       //클라이언트가 종료 메세지를 입력할 경우
         {          
           close(icSock[uiCnt]);            //해당 소켓을 닫고          
           --uiUser;                //uiUser 수를 줄여주고
           icSock[uiCnt] = icSock[uiUser];          //빠져나간 자리에 가장 마지막에 들어온 유저의 소켓 번호를 넣어준다
         }
       }
     }

   }
   for(uiCnt = 0; uiCnt < uiUser; ++uiCnt)          //종료시 열린 소켓을 모두 닫아준다.
   {
     close(icSock[uiCnt]);  
   }
   close(iSock);
   return 0;
 }
   
  


반응형
Posted by newind2000
Busan IT/공장내 Network2015. 8. 24. 17:45

==================================Outline====================================

select함수를 사용한 채팅 프로그램

----------------------------------------------------------------------------


select함수를 사용하여 멀티프로세스가 아닌 파일 디스크럽터 감시로 다중화 입출력을 처리한다. select함수의 단점은 채널의 수가 210승개(1024)로 제약된다는 점이다.


select함수로 감시할 파일을 지정하기 위해 FD_ZERO, FD_SET을 사용한다. 이 함수들을 사용하기 위해서 우선 fd_set 구조체를 선언해주어야 한다. FD_ZERO와 FD_SET의 인자로 생성한 fd_set구조체의 주소를 던져주어야 하기 때문이다.




fork함수를 활용하여 멀티 프로세스로 코딩하였던 채팅 프로그램을 select함수를 사용하여 만들어보자.


/*** client.c ***/

#include "smartsock.h"

int main(void)
{
  int iFd;
  struct sockaddr_in stAddr;
  int iLen;
  int iRtn;
  char cBuf[BUF_SIZE];  
  fd_set fdRead;


  /*** socket ***/
  iFd = socket(AF_INET, SOCK_STREAM, 0);
  if(-1 == iFd)
  {
    perror("socket:");
    return 100;
  }

  /*** structure setting ***/
  stAddr.sin_family = AF_INET;
  stAddr.sin_addr.s_addr = inet_addr(IP);
  stAddr.sin_port = htons(PORT);

  iLen = sizeof(struct sockaddr_in);

  /*** connect ***/
  iRtn = connect(iFd, (struct sockaddr *)&stAddr, iLen);
  if(-1 == iRtn)
  {
    perror("connect:");
    close(iFd);
    return 200;
  }

  while(1)
  {
    FD_ZERO(&fdRead);  
    FD_SET(0&fdRead);
    FD_SET(iFd, &fdRead);      
    select(iFd+1,&fdRead, 000);

    if(0 == (FD_ISSET(0&fdRead) ) )
    {
      memset(cBuf, 0, MSG_SIZE);
      iRtn = read(0, cBuf, MSG_SIZE);      
      cBuf[iRtn - 1= 0;
      write(iFd, cBuf, MSG_SIZE);
      printf("[Send MSG]: [%s]\n", cBuf);    
    }
    if(0 == (FD_ISSET(iFd, &fdRead) ))
    {
      memset(cBuf, 0, MSG_SIZE);
      iRtn = read(iFd, cBuf, MSG_SIZE);      
      printf("[Server]: [%s]\n", cBuf);    
    }
    if(0 == strncmp(cBuf, MSG_END, strlen(MSG_END)))
    {
      break;
    }    
  }

  

  /*** read & write ***/
  //memset(cBuf, 0, BUF_SIZE);
  //iRtn = read(0, cBuf, BUF_SIZE);
  

  close(iFd);
  return 0;
}

/*** server.c ***/

#include "smartsock.h"
#include <unistd.h>

int main(void)
{
  int iSock;   //소켓 함수의 반환 값을 받는 변수
  int icSock[MAX_USER];   //accept의 반환 값을 받는 변수
  int iRet;
  struct sockaddr_in stAddr;
  socklen_t uiSockLen=sizeof(struct sockaddr);
  char cBuff[BUF_SIZE];
  const char * cP;
  fd_set fdRead;
  unsigned int uiUser;
  unsigned int uiCnt;

  iSock = socket(AF_INET, SOCK_STREAM, 0);    //AF_INET = 2, 
  if(0 > iSock)
  {
    perror("socket : ");
    return -1;
  }
  // stAddr구조체에 socket연결을 위한 필수 정보 입력  setting
  bzero(&stAddr, sizeof(stAddr));            //구조체 비우기(0으로 채우기)
  stAddr.sin_family = AF_INET;               //#define AF_INET 2 /* IP protocol family. */
  stAddr.sin_addr.s_addr = inet_addr(IP);    //IP와 PORT값은 헤더파일에 정의되어 있다.
  stAddr.sin_port = htons((PORT));

  iRet = bind(iSock, (struct sockaddr *)&stAddr,sizeof(stAddr));
  if(iRet < 0)
  {
    perror("bind : ");
    close(iSock);

    return -2;
  }
  iRet = listen(iSock, 5);
  if(iRet != 0)
  {
    perror("listen : ");
    close(iSock);

    return -3;
  }
  uiUser = 0;
  while(1
  {
    FD_ZERO(0,&fdRead);
    FD_SET(0&fdRead);
    FD_SET(iSock, &fdRead);
    for(uiCnt = 0; uiCnt <= uiUsert; ++uiCnt)
    {
      FD_SET(icSock[uiCnt], &fdRead)
      
    }
    select((iSock+1+uiCnt), &fdRead, 000);

    if0 != FD_ISSET(iSock))
    {
      icSock[uiUser] = accept(iSock, (struct sockaddr *)&stAddr, &uiSockLen); //접속자의 정보가 stAddr에 입력된다.
      if(icSock[uiUser] < 0)
      {
        perror("Accept : ");
        continue;
      }
      ++uiUser;
      


    }




    if(pid ==  0)  
    {
      break;
    }
  }
  close(iSock);

  printf("Incoming Client \n");
  //cP = inet_ntoa(stAddr.sin_addr);
  printf("Client IP :%s\n", inet_ntoa(stAddr.sin_addr));
  printf("Client Port : %d\n", ntohs(stAddr.sin_port));  

  write(icSock, "Welcome :)"sizeof("Welcome :)"));

  while(1)
  {
    read(icSock, cBuff, MSG_SIZE);
    printf("[client]: [%s]\n", cBuff);

    write(icSock, cBuff, MSG_SIZE);
    if(0 == strncmp(MSG_END, cBuff, strlen(MSG_END) ) )
      break;

  }
  close(icSock);
  return 0;
}


/*** smartsock.h ***/


#ifndef __SMARTSOCK_H__
#include <sys/select.h>
#define __SMARTSOCK_H__

#include <stdio.h>
#include <string.h>
#include <strings.h>
// socket & bind & listen & accept & connect
#include <sys/types.h>
#include <sys/socket.h>

// sockaddr_in
#include <netinet/in.h>

// read & write
#include <unistd.h>

// htonl
#include <arpa/inet.h>

// errno, perror
#include <errno.h>

// open
#include <fcntl.h>
#include <sys/stat.h>

//select
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>

#define PORT      7777
#define IP        "192.168.0.173"

#define MSG_SIZE  255
#define BUF_SIZE  (MSG_SIZE+1)
#define MSG_END    "quit"

#define MAX_USER 30

#endif /* __SMARTSOCK_H__ */

client.c


server.c


smartsock.h


반응형
Posted by newind2000
Busan IT/공장내 Network2015. 8. 18. 16:54

==================================Outline====================================

select 함수

select함수를 사용한 채팅프로그램 작성

----------------------------------------------------------------------------

select 함수 



 

 

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

#include <stdio.h>

 

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

 

fd_set 구조체가 인자로 사용된다. fd_set 구조체의 크기는128byte, 1024bit이다. byte단위가 아닌 flag형식인 bit 단위로 1024bit를 1(set)과 0으로 조작한 후 select함수에 넣어 사용하게 될 것이다.

 

인자들(Arguments)

 

nfds

[입력] 버클리 소켓과 호환되는 소켓을 제외 하고는 이 매개변수는 무시됩니다. 버클리 소켓에서 이 매개변수는 I/O 변화를 감지 할 총 소켓의 갯수+1 의 값을 지정하는 용도로 사용합니다.

 

readfds

[/출력] 읽기상태의 변화를 감지할 소켓을 지정합니다.

 

writefds

[/출력] 쓰기상태의 변화를 감지할 소켓을 지정합니다.

 

exceptfds

[/출력] 예외상태 변화를 감지할 소켓을 지정합니다.

 

timeout

[입력] select 함수가 기다리기 위한 시간입니다. NULL 일경우 지정한 I/O변화가 발생했을 때까지 계속 기다립니다.


fd_set구조체 조작 함수들


FD_ZERO: fd_set 구조체에서 모든 비트를 0으로 채우는 함수

FE_SET: fd_set 구조체에서 선택 비트를 1로 채우는 함수

FD_CLR: fd_set 구조체에서 선택 비트를 0으로 채우는 함수 

FD_ISSET: fd_set 구조체해서 해당 비트의 상태를 반환하는 함수


select 함수

select함수의 Read, Write, Error 중에서 값이 set으로 된 것들만 감시하게 된다.

 

select는 블록킹 함수로써(scanf같은) 감시하던 파일들에서 이벤트가 발생 했을 때 블록 상태가 풀리게 된다.

 

select의 마지막 인자는 블록킹 대기 상태의 시간을 나타내며 ‘0’을 입력 시 무한대기 상태가 된다.

 

select 함수는 등록된 파일 중 데이터 변화가 생긴 개수를 반환하고 함수 실패 시 -1을 반환한다.

 

첫 번째 인자에서 감시하는 수에서 가장 큰 수에 +1 한 값을 넣어주면 된다.

 

select함수를 사용한 채팅프로그램 작성

 

select함수를 사용하면 멀티 프로세스 없이 채팅 프로그램을 작성할 수 있다.

 

전에 작성하던 헤더파일만 사용하고 serverclient채팅 프로그램을 다시 작성해보자.

 

우선 클라이언트부터 만든다.

 

클라이언트 채팅 프로그램을 만들기 위한 흐름은 아래와 같다.

 

socket() -> connect() -> read() & write() -> close()


/*** 소스 ***/

#include "smartsock.h"

int main(void)
{
  int iFd;
  struct sockaddr_in stAddr;
  int iLen;
  int iRtn;
  char cBuf[BUF_SIZE];
  fd_set fdRead;

  /*** socket ***/
  iFd = socket(AF_INET, SOCK_STREM, 0);
  if(-1 == iFd)
  {
    perror("socket:");
    return 100;
  }

  /*** structure setting ***/
  stAddr.sin_family = AF_INET;
  stAddr.sin_addr.s_addr = inet_addr(IP);
  stAddr.sin_port = htons(PORT);

  iLen = sizeof(struct sockaddr_in);

  /*** connect ***/
  iRtn = connect(iFd, (struct sockaddr *)&stAddr, iLen);
  if(-1 == iRtn)
  {
    perror("connect:");
    close(iFd);
    return 200;
  }

  while(1)
  {
    FD_ZERO(&fdRead);  
    FD_SET(0&fdRead);
    FD_SET(iFd, &fdRead);  //    
  }
  

  /*** read & write ***/
  memset(cBuf, 0, BUF_SIZE);
  iRtn = read(0, cBuf, BUF_SIZE);
  

  close(iFd);
  return 0;
}

 

반응형
Posted by newind2000
Busan IT/공장내 Network2015. 8. 13. 17:04

==================================Outline====================================

Hacker School level 1

VMware 해커스쿨 서버 설치

----------------------------------------------------------------------------

 

C에서 네트워크를 구현하는 방식은 select함수를 사용하면 된다.

 

select 함수의 인자에 fd_set이라는 구조체가 필요하다

 

 

....에서 해커스쿨 해킹 트레이닝을 해보자.

 

Hacker School level 1


ID: level1 / PS: level1으로 접속한다.

 

 

ls -al 명령어를 사용하여 파일과 디렉토리를 확인해보면 'hint'라는 파일이 눈에 들어온다.

 

이 파일을 cat'명령어로 열어보자.

 

 

level2권한이 있는 파일을 찾기 위해서는 검색이 필요하다.

 

ls -alR / 2 >/dev/null | grep level2명령어를 사용하여 level2가 있는 폴더를 검색해보자.

 

 

 

 

 

필요 없는 목록이 보고 싶지 않다면 2>/dev/null'를 사용하면 된다.

 

해당 파일을 실행 시킨다.

원하는 명령은 bash를 입력하고 level2의 비밀번호를 알아내기 위해 my-pass를 입력한다.

 

 

그리하면 level2의 비밀번호인 "hacker or cracker"가 나온다.

 

 

VMware 해커스쿨 서버 설치

 

VMware를 사용하여 해커스쿨 서버를 설치해보자. VMware Workstation을 실행시킨다.

 

File -> Open에서,

 

 

압축을 푼 WMware_FHZ서버에 있는 Red Hat Linux.vmx를 선택한다.

 

 

초록색 플레이 버튼을 눌러 실행시킨다.

 

 

 

서버를 실행시킨 후 비밀번호를 설정해 주자.

 

 

비밀번호 변동 명령어는 passwd이다.

 

 

네트워크 설정을 위해 setting으로 들어간다.

 

 

네트워크 어댑터에서 bridged에 체크 표시를 해준다. 이것을 통해 가상 머신은 물리적 네트워크에 접속할 수 있는 권한을 갖는다.

 

 

'setup'명령으로 가상 머신에 네트워크 설정을 해주자.

 

아래와 같이 설정을 해주고 'OK'를 눌러준다.

 

네트워크 설정이 바로 적용되지 않음으로 '/etc/init.d/network restart' 명령어를 사용하여 네트워크를 재시작 시켜준다.

 

‘ping' 명령어를 사용하여 네트워크가 제대로 동작하는지 확인한다.

 

 

이제 설정이 끝났으니 윈도우에서 도스명령어창을 실행하여 가상머신으로 만든 hacker school에 접속해보자!

 

아주 잘 된다!

반응형
Posted by newind2000
Busan IT/공장내 Network2015. 8. 10. 17:30

==================================Outline====================================

shmget 함수 - 공유 메모리 생성

shmat 함수

세마포어(임계영역에 대한 베타적인 권한)

시그널 - 소프트웨어 인터럽트

----------------------------------------------------------------------------

 

shmget 함수 - 공유 메모리 생성


 

리눅스에서 파일에 대한 권한을 살펴보면 Read-Write-Execute로 순서로 소유자, 그룹, 나머지에게 주어진 권한을 표시해준다. 이것을 2진수 개념으로 표시하여 각 권한 대상자에게 최대 7, 최소 0의 값이 주어진다.(권한 부여 = 1, 아닐 시 = 0)

 

shmat 함수


 

세마포어(임계영역에 대한 베타적인 권한)

 

동시에 제한된 자원을 할당받으려 할 때, 중복을 막기 위해 도입된 개념이 세마포어이다.

공유 메모리나 파이프 방식은 동시 접속을 통해 자원을 할당 받기 때문에 같은 자원을 요청할 경우 문제가 발생할 수 있다. 이를 해결하기 위한 도입된 개념이 동기화이다.

 

//kerner을 통해 세마포어를 사용하기 때문에 embedded MCU는 세마포어의 개념이 없다.

 

시그널 - 소프트웨어 인터럽트

 

ctrl + C 를 눌렀을 때 시그널을 활용하여 특정한 함수가 실행되도록 해보자.

 

리눅스에서 프로그램을 강제로 종료시킬 때

 

우선 실행중인 프로세스들을 본다.

 

ps -al

 

kill 명령어를 사용하여 죽여도 죽지 않으면

 

kill -9 “pid" 





 

반응형
Posted by newind2000
Busan IT/공장내 Network2015. 7. 28. 17:34

==================================Outline====================================

채팅 멀티프로세스

----------------------------------------------------------------------------

채팅 멀티프로세스 

리눅스에서는 프로그램의 리턴 값이 저장되고 echo $? 명령어를 사용하여 그 return 값을 출력할 수 있다.

//아무 일도 수행하지 않는 프로세스를 좀비 프로세스라고 한다.

 

fork함수를 사용하여 서버와 클라이언트의 멀티 프로세스 작업을 해보자.

 

우선 fork를 사용하기 위해여 헤더파일이 <unistd.h>를 추가해준다.

 

다음 fork함수의 리턴 값을 받기 위해 타입이 정의된 pid_t 변수를 하나 선언해 준다.

 

fork함수의 리턴 값이 0보다 크면 부모 프로세스이고 이 값은 프로세스 ID를 반환한다.

반면에 자식 프로세스는 0을 반환한다.

 

 

 

우선 fork함수를 통하여 클라이언트에서 쓰기/읽기를 분리하자.

writeread함수 무한 while문 전에 fork 함수를 사용하여 프로세스를 복사한다.

부모 프로세스에는 읽기/자식 프로세스는 쓰기만 하도록 if문을 사용하여 분리해준다.

 

 

서버에서는 랑데부 소켓(클라이언트 연결 전용)과 커뮤니케이션 소켓(통신전용)을 사용한다.

if문을 사용하여 분리한다.

 

/*** 소스 ***/


<server.c>

#include "smartsock.h"
#include <unistd.h>

int main(void)
{
  int iSock;   //소켓 함수의 반환 값을 받는 변수
  int icSock;   //accept의 반환 값을 받는 변수
  int iRet;
  struct sockaddr_in stAddr;
  socklen_t uiSockLen=sizeof(struct sockaddr);
  char cBuff[BUF_SIZE];
  const char * cP;
  pid_t pid;

  iSock = socket(AF_INET, SOCK_STREAM, 0);    //AF_INET = 2, 
  if(0 > iSock)
  {
    perror("socket : ");
    return -1;
  }
  // stAddr구조체에 socket연결을 위한 필수 정보 입력  setting
  bzero(&stAddr, sizeof(stAddr));            //구조체 비우기(0으로 채우기)
  stAddr.sin_family = AF_INET;               //#define AF_INET 2 /* IP protocol family. */
  stAddr.sin_addr.s_addr = inet_addr(IP);    //IP와 PORT값은 헤더파일에 정의되어 있다.
  stAddr.sin_port = htons((PORT));

  iRet = bind(iSock, (struct sockaddr *)&stAddr,sizeof(stAddr));
  if(iRet < 0)
  {
    perror("bind : ");
    close(iSock);

    return -2;
  }
  iRet = listen(iSock, 5);
  if(iRet != 0)
  {
    perror("listen : ");
    close(iSock);

    return -3;
  }
  while(1
  {
    icSock = accept(iSock, (struct sockaddr *)&stAddr, &uiSockLen); //접속자의 정보가 stAddr에 입력된다.

    if(icSock < 0)
    {
      perror("Accept : ");
      close(iSock);

      return -4;
    }
/////////////////////////////멀티 프로세스///////////////////////////////////////////
    pid = fork();

    if(pid ==  0)  //자식 프로세스이면 while문 break
    {
      break;
    }
  }
  close(iSock);

  printf("Incoming Client \n");
  //cP = inet_ntoa(stAddr.sin_addr);
  printf("Client IP :%s\n", inet_ntoa(stAddr.sin_addr));
  printf("Client Port : %d\n", ntohs(stAddr.sin_port));  

  write(icSock, "Welcome :)"sizeof("Welcome :)"));

  while(1)
  {
    read(icSock, cBuff, MSG_SIZE);
    printf("[client]: [%s]\n", cBuff);

    write(icSock, cBuff, MSG_SIZE);
    if(0 == strncmp(MSG_END, cBuff, strlen(MSG_END) ) )
      break;

  }
  close(icSock);
  return 0;
}

<client.c>

#include "smartsock.h"
#include <unistd.h>

int main(void)
{
  struct sockaddr_in stAddr;
  int iSock;
  int iRet;
  char cBuff[BUF_SIZE];
  socklen_t uiSockLen=sizeof(struct sockaddr);
  pid_t pid;

  iSock = socket(AF_INET, SOCK_STREAM, 0);
  if(0 > iSock)
  {
    perror("socket : ");
    return -1;
  }

  bzero(&stAddr, sizeof(stAddr));
  stAddr.sin_family = AF_INET;

  stAddr.sin_addr.s_addr = inet_addr("192.168.0.173");
  stAddr.sin_port = htons((PORT));

  iRet = connect(iSock, (struct sockaddr *)&stAddr, uiSockLen);
  if(0 > iRet)
  {
    perror("connect : ");
    return -2;
  }

  pid = fork();

  if(pid > 0)
  {
    close(0);
    while(1)
    {
      read(iSock, cBuff, MSG_SIZE);
      printf("[server]: [%s]\n", cBuff);

      if(0 == strncmp(MSG_END, cBuff, strlen(MSG_END)))
        break;
    }

  }
  else
  {
    close(1);
    while(1)
    {
      iRet = read(0, cBuff, MSG_SIZE);
      cBuff[iRet-1= 0;
      write(iSock, cBuff, MSG_SIZE);

    }

  }

  close(iSock);
  return 0;
}

 

여러 개의 클라이언트가 접속했음을 알 수 있다.





멀티 프로세서 분리된 서버/클라이언트의 통신은 가능하지만 서버 간의 통신이 없기 때문에 분리된 클라이언트들은 다른 클라이언트가 서버로 보낸 메시지를 볼 수 없다. 때문에 PIC(Internal Process Communication)이 필요하다.

 

To be continued...

 

반응형

'Busan IT > 공장내 Network' 카테고리의 다른 글

Hacker School level 1, VMware 해커스쿨 서버 설치  (0) 2015.08.13
IPC(3)  (0) 2015.08.10
Three-way Handshake, fork 함수, execl 함수  (0) 2015.07.24
TCP analyzer  (0) 2015.07.22
TCP analyzer(진행 중)  (0) 2015.07.17
Posted by newind2000
Busan IT/공장내 Network2015. 7. 24. 17:35

================================ Outline ====================================

Three-way Handshake

fork 함수

execl 함수

----------------------------------------------------------------------------

 

Three-way Handshake

 

 

서로 SYNC번호를 주고 받음으로써 serverclient의 통신 여부를 확인하는 절차다. client에서 SYNC번호를 보내면 server에서는 SYNC 번호를 확인하고 자신의 SYNC번호도 client에게 보내게 된다. SYNC번호를 확인했다는 뜻으로 전송 받은 SYNC번호에 1을 더하여 ACK번호로 client에게 보내게 된다. Clientserver에게 보낸 SYNC번호를 확인했다는 뜻으로 SYNC번호에 1을 더한 것을 ACK로 보내면 통신이 연결되게 된다.

 

 

connectaccept에서 일어난다.

 

 

연결 종료 시에는 serverFIN flagset을 입력하여 전송하고 client가 이를 받고난 후 FIN flagset를 시켜 다시 서버에게 전송하게 된다.

close에서 일어난다.

 

 

 

채팅 프로그램을 계속해서 만들어보자.

 

채팅 시 clientserver가 작성 중이라도 상대방이 전송한 내용을 읽어 들여야 하기 때문에 이를 해결 위해 스레드 혹은 멀티 프로세스를 사용해야 한다.

 

교재 p/227 ch.10 멀티 프로세스 소켓 프로그래밍

 

//프로젝트를 실행할 때 단위테스트(새롭게 사용하는 함수, 실행단위)를 거치고 난 후 테스트가 성공해야 코딩을 지속한다.

 

fork 함수

 

fork함수를 테스트해보자.

 

 

 

 

/*** 소스 ***/

#include <unistd.h>
#include <stdio.h>
#include <errno.h>

int main(void)
{
  int iNum;
   iNum = fork();  //multy process init

  if(0 >  iNum)
  {
    perror("fork::");
    return -1;
  }
  else if(0 == iNum)
  {
    printf("Child Process\n");
    getchar();
    printf("Child About to abort\n");
  }
  else
  {
    printf("Parent Process ID[%d]\n", iNum);
    getchar();
    printf("Parent About to abort\n");

  }

  return 0;
}  

 

fork함수의 속성

 

- 지역 변수 값 및 전역 변수 값은 복사된다.

- 소켓을 포함한 모든 열린 파일의 파일 지정번호가 복사된다.

- 부모프로세스나 자식프로세스가 중 하나가 종료 되었을 때 남은 프로세스에게 신호(signal)을 보낸다.

 

 

execl 함수

 

execl 함수는 외부 프로그램을 멀티 프로세스를 통해 실행시켜주는 함수이다.

 

/*** 소스 ***/

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main(void)
{
  printf("--------start--------\n");
  execl("/bin/ls""ls", NULL);
  printf("---------end---------\n");



  return;

}

 


반응형

'Busan IT > 공장내 Network' 카테고리의 다른 글

IPC(3)  (0) 2015.08.10
채팅 멀티프로세스  (0) 2015.07.28
TCP analyzer  (0) 2015.07.22
TCP analyzer(진행 중)  (0) 2015.07.17
TCP 추출(진행중)  (0) 2015.07.16
Posted by newind2000
Busan IT/공장내 Network2015. 7. 22. 17:43

================================ Outline ====================================

TCP analyzer

----------------------------------------------------------------------------




 

접속 시 SYN1이 연속으로 두 번 캡쳐 된다.

 /*** 소스 ***/

 

#include <stdio.h>
#include <netinet/in.h>
#include <pcap/pcap.h>
#include <net/ethernet.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>

int main(void)
{
  char*           cpNICName;
  char           caErrMSG[PCAP_ERRBUF_SIZE];
  int           iCnt;
  unsigned char const *   ucpData;
  pcap_t*         stpDS;
  struct pcap_pkthdr     stInfo;
  struct tcphdr *     stTcp;
  struct ip *        stpIp;  


  cpNICName = pcap_lookupdev(caErrMSG);

  if(0 == cpNICName)
  {
    printf("ERRMSG  : [%s]\n",caErrMSG);
    return 100;
  }

  stpDS = pcap_open_live(cpNICName, ETH_DATA_LEN, 10, caErrMSG);

  printf("Packet Monitoring Start....\n");
  getchar();

  while(1)
  {
    ucpData = pcap_next(stpDS, &stInfo);

    if(ETH_P_IP != ntohs(*(unsigned short*)(ucpData+12))) // 2byte 二쇱냼
    {
      continue;
    }

    if(IPPROTO_TCP != *(ucpData+23))
    {
      continue;
    }


    stpIp = (struct ip *) (ucpData + sizeof(struct ether_header));
    stTcp = (struct tcphdr *)(ucpData + sizeof(struct ether_header) 
        + ((*(ucpData+ sizeof(struct ether_header)) & 0x0F) * 4));

    printf("=============================================\n");
    printf("[%s:%d] ---> [%s:%d]\n"
        , inet_ntoa(stpIp -> ip_src)
        , ntohs(stTcp -> source)
        , inet_ntoa(stpIp -> ip_dst)
        , ntohs(stTcp -> dest)
        );

    printf("SYN[%d] ACK[%d] Seq[%010u] Ack[%010u]\n"
        , stTcp -> syn
        , stTcp -> ack
        , ntohl(stTcp -> seq)
        , ntohl(stTcp -> ack_seq)
        );
  }

  pcap_close(stpDS);

  return 0;
}


 

Three-way Hand Shake... yeah

 

 

 

 

반응형

'Busan IT > 공장내 Network' 카테고리의 다른 글

채팅 멀티프로세스  (0) 2015.07.28
Three-way Handshake, fork 함수, execl 함수  (0) 2015.07.24
TCP analyzer(진행 중)  (0) 2015.07.17
TCP 추출(진행중)  (0) 2015.07.16
Echo Server/Client  (0) 2015.07.15
Posted by newind2000