C connect() 서버로 접속 요청 함수
inet_addr() 함수는 숫자와 점으로 이루어진 IP 문자열을 long형의 숫자 IP 주소로 바꾸어 줍니다. struct sockaddr_in 에서 .sin_addr.s_add 값을 long형의 숫자 IP값을 넣어 주어야 하는데 이 때 사용됩니다.
- 헤더: sys/types.h, sys/socket.h
- 형태: int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen)
- 인수: int sockfd 소켓 디스크립터
struct sockaddr *serv_addr 서버 주소 정보에 대한 포인터
socklen_t addrlen struct sockaddr *serv_addr 포인터가 가르키는 구조체의 크기 - 반환: -1 == 실패, -1 이외 새로운 소켓 디스크립터
인수 추가 설명
int socket(int domain, int type, int protocol);
int domain : 인터넷을 통해 통신할 지, 같은 시스템 내에서 프로세스 끼리 통신할 지의 여부를 설정합니다.
domain | 내용 |
PF_INET, AF_INET | IPv4 인터넷 프로토콜을 사용합니다. |
PF_INET6 | IPv6 인터넷 프로토콜을 사용합니다. |
PF_LOCAL, AF_UNIX | 같은 시스템 내에서 프로세스 끼리 통신합니다. |
PF_PACKET | Low level socket 을 인터페이스를 이용합니다. |
PF_IPX | IPX 노벨 프로토콜을 사용합니다. |
int type : 데이터의 전송 형태를 지정하며 아래와 같은 값을 사용할 수 있습니다.
type | 내용 |
SOCK_STREAM | TCP/IP 프로토콜을 이용합니다. |
SOCK_DGRAM | UDP/IP 프로토콜을 이용합니다. |
TCP/IP 통신 함수 사용 순서
TCP/IP 예제 소개
TCP/IP 예제를 서버와 클라이언트로 나누어서 설명을 드리도록 하겠습니다.
- 서버와 클라이언트는 port 4000번 사용
- 클라이언트프로그램에서 서버에 접속하면 실행할 때 입력받은 문자열을 전송
- 서버는 클라이언트로부터 자료를 수신하면 문자열 길이와 함께 수신한 문자열을 클라이언트로 전송
서버 프로그램
서버 프로그램에서 사용해야할 함수와 순서는 아래와 같습니다.
우선 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 에 필요한 정보를 할당하고 커널에 등록
- 만들어진 server_socket 은 단지 socket 디스크립터일 뿐입니다.
- 이 socket에 주소를 할당하고 port 번호를 할당해서 커널에 등록해야 합니다.
- 커널에 등록해야 다른 시스템과 통신할 수 있는 상태가 됩니다.
- 더 정확히 말씀드린다면 커널이 socket 을 이용하여 외부로부터의 자료를 수신할 수 있게 됩니다.
- 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); }
- htonl( INADDR_ANY) 는 주소를 지정해 주는 것으로 inet_addr( "내 시스템의 IP ")로도 지정할 수 있습니다. 그러나 프로그램이 실행되는 시스템 마다 IP 가 다를 것이므로 주소 지정을 고정 IP로 하지 않고 htonl( INADDR_ANY) 를 사용하는 것이 편리합니다.
이제 listen() 함수로 클라이언트 접속 요청을 확인합니다.
if( -1 == listen( server_socket, 5)){
printf( "대기상태 모드 설정 실패\n");
exit( 1);
}
클라이언트 접속 요청에 따라 accept()로 접속을 허락합니다.
- accept()로 접속 요청을 허락하게 되면 클라이언트와 통신을 하기 위해서 커널이 자동으로 소켓을 생성합니다.
- 이 소켓을 client socket이라고 하겠습니다.
- client socket 정보를 구하기 위해 변수를 선언합니다. 그리고 client 주소 크기를 대입합니다.
int client_addr_size; client_addr_size = sizeof( client_addr);
- 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);
- read() 를 이용하여 클라이언트로부터 전송된 자료를 읽어 들입니다.
- 만일 클라이언트로부터 전송된 자료가 없다면 송신할 때 까지 대기하게 됩니다. 즉, 블록된 모습이 됩니다.
이번에는 wirte() 함수를 이용하여 클라이언트도 데이터를 전송합니다.
- 수신된 데이터의 길이를 구하여 전송 데이터를 준비합니다.
sprintf( buff_snd, "%d : %s", strlen( buff_rcv), buff_rcv);
- write() 를 이용하여 클라이언트로 자료를 송신합니다.
write( client_socket, buff_snd, strlen( buff_snd)+1); // +1: NULL까지 포함해서 전송
- 작업이 완료되면 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()를 이용하여 서버로 접속을 시도합니다.
- 주소 정보에 서버의 주소와 포트번호를 지정하고
- 서버와의 연결을 시도합니다.
- 예제에서는 시스템 자기를 가르키는 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); }
- 접속에 성공하면 데이터를 전송합니다.
write( client_socket, argv[1], strlen( argv[1])+1); // +1: NULL까지 포함해서 전송
- 자료를 수신하고 화면에 출력합니다.
read ( client_socket, buff, BUFF_SIZE); printf( "%s\n", buff);
- 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
]$
'컴퓨터 > 프로그래밍' 카테고리의 다른 글
C언어 클라이언트 접속 요청 수락 함수 accept() (0) | 2020.03.16 |
---|---|
C언어 클라이언트 접속 요청을 받을 수 있도록 설정 함수 listen() (0) | 2020.03.16 |
C언어 IP 문자열에서 long 형 숫자 IP주소 구하기 함수 inet_addr() (0) | 2020.03.16 |