본문으로 바로가기
homeimage
  1. Home
  2. 컴퓨터/프로그래밍
  3. C언어 소켓에 IP주소와 포트번호 지정 함수 bind()

C언어 소켓에 IP주소와 포트번호 지정 함수 bind()

· 댓글개 · 바다야크

C bind() 소켓에 IP주소와 포트번호 지정 함수

socket() 함수는 소켓을 생성하여 반환합니다.

  • 헤더: sys/types.h, sys/socket.h
  • 형태: int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen)
  • 인수: int sockfd 소켓 디스크립터
    struct sockaddr *myaddr 주소 정보
    socklen_t addrlen myadd 구조체의 크기
  • 0 == 성공, -1 == 실패

인수 추가 설명

int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen)

struct sockaddr *myaddr 주소 정보로 인터넷을 이용하는 AF_INET인지 시스템 내에서 통신하는 AF_UNIX에 따라서 달라집니다. 인터넷을 통해 통신하는 AF_INET인 경우에는 struct sockaddr_in을 사용합니다.

struct sockaddr_in {
   sa_family_t            sin_family;       /* Address family        */
   unsigned short int    sin_port        /* Port number            */
   struct in_addr        sin_addr;         /* Internet address        */
   
   /* Pad to size of ´struct sockaddr'. */
   unsigned char  __pad[__SOCK_SIZE__ - sizeof(short int) -
      sizeof(unsigned short int) - sizeof(struct in_addr)];
};

시스템 내부 통신인 AF_UNIX인 경우에는 struct sockaddr을 사용합니다.

struct sockaddr {
   sa_family_t  sa_family;   /* address family, AF_xxx    */
   char        sa_data[14];  /* 14 bytes of protocol address    */
};

TCP/IP 통신 함수 사용 순서

TCP/IP 예제 소개

TCP/IP 예제를 서버와 클라이언트로 나누어서 설명을 드리도록 하겠습니다.

  1. 서버와 클라이언트는 port 4000번 사용
  2. 클라이언트프로그램에서 서버에 접속하면 실행할 때 입력받은 문자열을 전송
  3. 서버는 클라이언트로부터 자료를 수신하면 문자열 길이와 함께 수신한 문자열을 클라이언트로 전송

서버 프로그램

서버 프로그램에서 사용해야할 함수와 순서는 아래와 같습니다.

우선 socket 부터 만들어야 합니다. TCP/IP에서는 SOCK_STREAM을, UDP/IP에서는 SOCK_DGRAM을 사용합니다.

int     server_socket;

server_socket = socket( PF_INET, SOCK_STREAM, 0);
if (-1 == server_socket)
{
   printf( "server socket 생성 실패");
   exit( 1) ;
}

bind() 함수를 이용하여 socket에 server socket 에 필요한 정보를 할당하고 커널에 등록

  1. 만들어진 server_socket 은 단지 socket 디스크립터일 뿐입니다.
  2. 이 socket에 주소를 할당하고 port 번호를 할당해서 커널에 등록해야 합니다.
  3. 커널에 등록해야 다른 시스템과 통신할 수 있는 상태가 됩니다.
  4. 더 정확히 말씀드린다면 커널이 socket 을 이용하여 외부로부터의 자료를 수신할 수 있게 됩니다.
  5. socket에 주소와 port 를 할당하기 위해 sockaddr_in 구조체를 이용합니다.
    struct sockaddr_in server_addr;
    
    memset( &server_addr, 0, sizeof( server_addr);
    server_addr.sin_family      = AF_INET;           // IPv4 인터넷 프로토롤
    server_addr.sin_port        = htons( 4000);      // 사용할 port 번호는 4000
    server_addr.sin_addr.s_addr = htonl( INADDR_ANY);// 32bit IPV4 주소
    
    if( -1 == bind( server_socket, (struct sockaddr*)&server_addr, sizeof( server_addr) ) ){
       printf( "bind() 실행 에러\n");
       exit( 1);
    }
  6. htonl( INADDR_ANY) 는 주소를 지정해 주는 것으로 inet_addr( "내 시스템의 IP ")로도 지정할 수 있습니다. 그러나 프로그램이 실행되는 시스템 마다 IP 가 다를 것이므로 주소 지정을 고정 IP로 하지 않고 htonl( INADDR_ANY) 를 사용하는 것이 편리합니다.

이제 listen() 함수로 클라이언트 접속 요청을 확인합니다.

if( -1 == listen( server_socket, 5)){
    printf( "대기상태 모드 설정 실패\n");
    exit( 1);
}

클라이언트 접속 요청에 따라 accept()로 접속을 허락합니다.

  1. accept()로 접속 요청을 허락하게 되면 클라이언트와 통신을 하기 위해서 커널이 자동으로 소켓을 생성합니다. 
  2. 이 소켓을 client socket이라고 하겠습니다.
  3. client socket 정보를 구하기 위해 변수를 선언합니다. 그리고 client 주소 크기를 대입합니다.
     int  client_addr_size;
    
    client_addr_size = sizeof( client_addr);
  4. accept()를 호출 후에 에러가 없으면 커널이 생성한 client socket 을 반환해 줍니다.
    client_socket = accept( server_socket, (struct sockaddr*)&client_addr,
                                                              &client_addr_size);
    if ( -1 == client_socket){
       printf( "클라이언트 연결 수락 실패\n");
       exit( 1);
    }

이제 client socket까지 만들어 졌으므로 read(), write() 함수를 이용하여 자료를 송수신 할 수 있습니다. read() 함수를 이용하여 클라이언트로부터 전송되어 오는 자료를 읽어 들입니다.

read ( client_socket, buff_rcv, BUFF_SIZE);
  1. read() 를 이용하여 클라이언트로부터 전송된 자료를 읽어 들입니다.
  2. 만일 클라이언트로부터 전송된 자료가 없다면 송신할 때 까지 대기하게 됩니다. 즉, 블록된 모습이 됩니다.

이번에는 wirte() 함수를 이용하여 클라이언트도 데이터를 전송합니다.

  1. 수신된 데이터의 길이를 구하여 전송 데이터를 준비합니다.
     sprintf( buff_snd, "%d : %s", strlen( buff_rcv), buff_rcv);
  2. write() 를 이용하여 클라이언트로 자료를 송신합니다.
    write( client_socket, buff_snd, strlen( buff_snd)+1); // +1: NULL까지 포함해서 전송
  3. 작업이 완료되면 close() 를 이용하여 client socket 을 소멸 시켜 데이터 통신을 종료합니다.
    close( client_socket);

클라이언트 프로그램

클라이언트 프로그램은 서버에 비해 간단합니다. 바로 설명 들어갑니다.

socket() 을 이용하여 소켓을 먼저 생성합니다.

int     client_socket;

client_socket = socket( PF_INET, SOCK_STREAM, 0);
if( -1 == client_socket)
{
   printf( "socket 생성 실패\n");
   exit( 1);
}

connect()를 이용하여 서버로 접속을 시도합니다.

  1. 주소 정보에 서버의 주소와 포트번호를 지정하고
  2. 서버와의 연결을 시도합니다.
  3. 예제에서는 시스템 자기를 가르키는 IP, 127.0.0.1 을 사용했습니다.
    struct sockaddr_in    server_addr;
    
    memset( &server_addr, 0, sizeof( server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons( 4000);
    server_addr.sin_addr.s_addr= inet_addr( "127.0.0.1");  // 서버의 주소
    
    if( -1 == connect( client_socket, (struct sockaddr*)&server_addr, sizeof( server_addr) ) ){
       printf( "접속 실패\n");
       exit( 1);
    }
  4. 접속에 성공하면 데이터를 전송합니다.
      write( client_socket, argv[1], strlen( argv[1])+1); // +1: NULL까지 포함해서 전송
  5. 자료를 수신하고 화면에 출력합니다.
    read ( client_socket, buff, BUFF_SIZE);
    printf( "%s\n", buff);
  6. socket 을 소멸하여 통신 작업을 완료합니다.
    close( client_socket);

서버 프로그램 소스

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

#define  BUFF_SIZE   1024

int   main( void)
{
   int   server_socket;
   int   client_socket;
   int   client_addr_size;

   struct sockaddr_in   server_addr;
   struct sockaddr_in   client_addr;

   char   buff_rcv[BUFF_SIZE+5];
   char   buff_snd[BUFF_SIZE+5];

   server_socket  = socket( PF_INET, SOCK_STREAM, 0);
   if( -1 == server_socket){
      printf( "server socket 생성 실패\n");
      exit( 1);
   }
   memset( &server_addr, 0, sizeof( server_addr));
   server_addr.sin_family     = AF_INET;
   server_addr.sin_port       = htons( 4000);
   server_addr.sin_addr.s_addr= htonl( INADDR_ANY);

   if( -1 == bind( server_socket, (struct sockaddr*)&server_addr,
               sizeof( server_addr) ) ){
      printf( "bind() 실행 에러\n");
      exit( 1);
   }
   if( -1 == listen(server_socket, 5)){
      printf( "listen() 실행 실패\n");
      exit( 1);
   }
   while( 1){
      client_addr_size  = sizeof( client_addr);
      client_socket     = accept( server_socket, (struct sockaddr*)&client_addr,
	                         &client_addr_size);

      if ( -1 == client_socket){
         printf( "클라이언트 연결 수락 실패\n");
         exit( 1);
      }
      read ( client_socket, buff_rcv, BUFF_SIZE);
      printf( "receive: %s\n", buff_rcv);
      
      sprintf( buff_snd, "%d : %s", strlen( buff_rcv), buff_rcv);
      write( client_socket, buff_snd, strlen( buff_snd)+1); // +1: NULL까지 포함해서 전송
      close( client_socket);
   }
}

클라이언트 프로그램 소스

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

#define  BUFF_SIZE   1024

int   main( int argc, char **argv)
{
   int   client_socket;
   struct sockaddr_in   server_addr;
   char   buff[BUFF_SIZE+5];

   client_socket  = socket( PF_INET, SOCK_STREAM, 0);
   if( -1 == client_socket){
      printf( "socket 생성 실패\n");
      exit( 1);
   }
   memset( &server_addr, 0, sizeof( server_addr));
   server_addr.sin_family     = AF_INET;
   server_addr.sin_port       = htons( 4000);
   server_addr.sin_addr.s_addr= inet_addr( "127.0.0.1");

   if( -1 == connect( client_socket, (struct sockaddr*)&server_addr,
                                  sizeof( server_addr) ) ){
      printf( "접속 실패\n");
      exit( 1);
   }
   write( client_socket, argv[1], strlen( argv[1])+1);      // +1: NULL까지 포함해서 전송
   read ( client_socket, buff, BUFF_SIZE);
   printf( "%s\n", buff);
   close( client_socket);
   
   return 0;
}

실행 결과

]$ gcc server.c -o server    // 서버 프로그램을 server 이름으로 컴파일
]$ gcc client.c -o client    // 클라이언트 프로그램을 client 이름으로 컴파일
]$ ./server &                // 서브 프로그램을 백그라운드로 실행
[1] 25869
]$ ./client test_string      // 클라이언트를 문자열을 입력하여 실행
receive: test_string
11 : test_string
]$ ./client badayak.com
receive: badayak.com
11 : badayak.com
]$
SNS 공유하기
💬 댓글 개
최근글
이모티콘창 닫기
울음
안녕
감사해요
당황
피폐

이모티콘을 클릭하면 댓글창에 입력됩니다.