블로그 이미지
하루, 글. 그림. 영상매체. 표현을 도와주는 기기들. 도전 중. 동화다아아

카테고리

분류 전체보기 (176)
잡담 (1)
IT 기기-리뷰&뉴스 (7)
리뷰 - 도서 (1)
리뷰 - 영상 (0)
리뷰 - 그림/음악 (1)
내장형 하드웨어 (163)
Total635,284
Today31
Yesterday129
// server.c
#include<stdio.h>

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

#define MAXCLIENT 2

int main()
{  
  int iDs;
  int maxDs; // 파일디스크립터 설정을 위한 변수
  int iAccept;
  int iaClient[MAXCLIENT]; // 접속 가능한 인원 수 - 소켓 번호를 가지고 있다.
  
  fd_set fsStatus; //
  int iCNum = 0// 접속자 수(client number)
  int iCounter; // 반복문을 위한 변수
  int iAddSize; 
  int iRet;
  unsigned char ucBuf[256];
  struct sockaddr_in stAddr; // 서버 주소 구조체
  struct sockaddr_in stAccept;
  
  iAddSize = sizeof(struct sockaddr_in);
  bzero(&stAddr, sizeof(stAddr)); // 0으로 구조체 초기화  
  // TCP를 사용하여 스트림 소켓을 연다.(반환형은 int)
  // 첫번째 인자는 IP protocol family - 2층 선택
  // 두번째 인자는 TCP설정, 세번째 인자는 Transmission Control Protocol - 3층
  iDs = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if(iDs<0// 예외 처리 - 소켓 생성에 실패했을 때
    {
    perror("socket() failed");
    close(iDs); // 열었던 소켓을 닫는다.  
        return -10;
    }
  stAddr.sin_family = AF_INET; // socket()의 첫번째 인자와 같다.
  // 주소 변환
  iRet = inet_pton(AF_INET, "192.168.10.49"&stAddr.sin_addr.s_addr);
  if(iRet == 0)
  {
    printf("inet_pton() failed""invalid address string");
    close(iDs); // 열었던 소켓을 닫는다.  
    return -100;
  }
  else if(iRet < 0)
  {
    perror("inet_pton() failded");  
    close(iDs); // 열었던 소켓을 닫는다.  
    return -100;
  }
  // ip 출력  
  printf("IP : %s\n", inet_ntoa(stAddr.sin_addr));
  // 서버 포트(포트 문을 열어준다.)
  stAddr.sin_port = htons(3000); // 포트 3000번 연다.
          // 여기까지가 기본 세팅이며 client와 동일하다.
  
  // 여기부터 client와 달라진다.
  // 지역 주소에 바인드(bind-소켓에 이름을 묶는다.)
  // 소켓 세팅(윈도우 레지스트 함수랑 유사)
  if(0>bind(iDs, (struct sockaddr *)&stAddr, iAddSize))
  {
    perror("bind() failed");
    close(iDs); // 열었던 소켓을 닫는다.  
    return -100;
  }
  // 소켓이 들어오는 요청을 처리할 수 있도록 설정(listen)  
  if(0>listen(iDs, 5)) 
  {
    perror("listen() failed");
    close(iDs);
    return -100;
  }

  maxDs = iDs+1// +1 하지 않으면 select가 한 비트 앞까지만 검사한다.
  while(1)
  {
    printf("현재 접속자 수 %d\n", iCNum); // 접속자 수 표시
    
    // 소켓 식별자 벡터를 '0'으로 초기화 하고 서버 소켓이 사용하도록 설정
    FD_ZERO(&fsStatus); // select()가 호출된후 매번 '0'으로 초기화
    // 랑데뷰 소켓
    FD_SET(iDs, &fsStatus);  // 디스크립터, 소켓식별자 벡터
  
    for(iCounter=0;iCNum-1>iCounter;++iCounter)
    {
      FD_SET(iaClient[iCounter], &fsStatus);
    }
    printf("TEST\n");
    // 파일디스크립터, 입력, 출력, 에러, 타임아웃(감시하는 시간-NULL은 무한대기)
    // 해당하는 소켓에 입력이 없으면 BLOCK 된다.
    // accept는 select가 통과시켜 주어야 호출된다.
    if(0 > select(maxDs, &fsStatus, NULL, NULL, NULL))
    {
      perror("select() error... ");
      close(iDs);
      return -100;
    }
    printf("Select End\n");
    // 클라이언트의 연결을 기다림(accept-소켓에 연결을 받아들인다.)
    // accept는 소캣을 새로 만들어 소켓이 두개가 된다. 그리고 소켓에 번호(파일디스크립터)가 할당된다.
    // 위에서 만든 소켓은 랑데뷰 소켓(분류만 담당한다. 실제 일은 하지 않는다.)
    // 실제 통신이 시작된다. - 접속자가 늘어날때마다 소켓이 계속 생성된다.
    iAccept = accept(iDs, (struct sockaddr *)&stAccept, &iAddSize);
    if(0>iAccept)  
    {
      perror("accept() error");
      close(iDs); // 랑데뷰 함수를 닫는다.
      // 들어온 접속자 만큼 닫는다.- 접속자가 없으면 돌지 않는다.
      for(iCounter=0;iCNum>iCounter;++iCounter)
      {
        close(iaClient[iCounter]);
      }
      return -100;
    }
    // 접속 제한 인원보다 많이 들어 왔을 때
    if(MAXCLIENT <= iCNum)
    {
      write(iAccept, "Server is full connection\n"sizeof("Server is full connection\n"));
      close(iAccept);
      continue ;
    }
    // 중간에 빈 파일디스크립터로 생성되었을 경우에는 더하면 안되므로
    if(iAccept == maxDs)
    {
      maxDs = iAccept + 1;   
      iaClient[iCNum] = iAccept;
      ++iCNum;
    }    
  
    // 접속이 오면 상대방 IP가 출력된다.  
    // 파일로 생각하면 완전히 파일이 열린 상태
    printf("Client IP : [%s]\n", inet_ntoa(stAccept.sin_addr));
  }
  // 저수준으로 읽는다. ucBuf의 길이를 알기 위해 iRet로 반환값을 저장한다.
  iRet = read(iAccept, ucBuf, sizeof(ucBuf));
  ucBuf[iRet] = 0;
  printf("%s\n", ucBuf);
  write(iAccept, "pong"sizeof("pong"));
  
    
  close(iDs); // 열었던 소켓을 닫는다.  
  close(iAccept);
  return 0;
}





// client.c
#include<stdio.h>

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

int main()
{
  int iDs;
  int iDSize;
  int iRet;
  unsigned char ucBuf[256];
  
  struct sockaddr_in stAddr; // 서버 주소 구조체

  iDSize = sizeof(struct sockaddr_in);
  bzero(&stAddr, iDSize); // 0으로 구조체 초기화  
  
  // TCP를 사용하여 스트림 소켓을 연다.(반환형은 int)
  // 첫번째 인자는 IP protocol family - 2층 선택
  // 두번째 인자는 TCP설정, 세번째 인자는 Transmission Control Protocol - 3층
  iDs = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if(iDs<0// 예외 처리 - 소켓 생성에 실패했을 때
    {
    perror("socket() failed");
    close(iDs);
        return -10;
    }
  stAddr.sin_family = AF_INET; // socket()의 첫번째 인자와 같다.
  // 주소 변환
  iRet = inet_pton(AF_INET, "192.168.10.47"&stAddr.sin_addr.s_addr);
  if(iRet == 0)
  {
    printf("inet_pton() failed""invalid address string");
    close(iDs);
        return -10;
  }
  else if(iRet < 0)
  {
    perror("inet_pton() failded");  
    close(iDs);
        return -10;
  }
  // ip 출력  
  printf("IP : %s\n", inet_ntoa(stAddr.sin_addr));
  // 서버 포트
  stAddr.sin_port = htons(3000);

  // 에코 서버에 연결 설정(connect) - 소켓 연결을 시작한다.
  // connect는 접속하기 전까지 client가 알 수 없다. 운영체제가 랜덤 생성
  // connect와 accept가 쌍을 이루고 3hand shake가 일어난다.
  if(0 > connect(iDs, (struct sockaddr *)&stAddr, iDSize))
  {
    perror("connect() failed");
    close(iDs);
    return -10;
  }
  write(iDs, "ping" , sizeof("ping"));
  iRet = read(iDs, ucBuf, sizeof(ucBuf));
  ucBuf[iRet] = 0;
  printf("%s\n", ucBuf);
  
  close(iDs); // 열었던 소켓을 닫는다.  
  return 0;
}


 
-> 실행 결과(Server)

 
-> 실행 결과(Client-  Telnet)
-> 접속제한 인원이 되어 서버로 부터 연결이 끊어지는 모습

Posted by 동화다아아

댓글을 달아 주세요

  1. 2011.11.17 14:20 Moonjs  댓글주소  수정/삭제  댓글쓰기

    죄송하지만 이거 실행이 안되는데 왜 안될까여??

    • 2011.11.18 08:29 신고 동화다아아  댓글주소  수정/삭제

      client쪽 실행시 telnet을 이용해서 해보셨는지요?
      telnet 192.168.xx.xx(IP) 3000(포트번호)
      와 같은 식으로 해보시면 됩니다. client없이 server만 가지고 실행 되실거에요. telnet으로 client 역활을 대신 하는 겁니다.ㅎㅎ

  2. 2012.05.25 17:14 철든잔차  댓글주소  수정/삭제  댓글쓰기

    좋은정보 감사합니다. 많은도움되었네요

  3. 2015.11.21 05:13  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

최근에 달린 댓글

최근에 받은 트랙백

글 보관함