TCP/IP 소켓 프로그램을 작성해 보겠습니다. 본 포스트는 동영상을 먼저 보신 후, 본문 내용을 보시면 이해하시기 편합니다.
TCP/IP 통신 함수 사용 순서
TCP/IP 예제 소개
TCP/IP 예제를 서버와 클라이언트로 나누어서 설명을 드리도록 하겠습니다.
- 서버와 클라이언트는 port 4000번을 사용
- 클라이언트프로그램에서 서버에 접속하면 실행할 때 입력받은 문자열을 전송
- 서버는 클라이언트로부터 자료를 수신하면 문자열 길이와 함께 수신한 문자열을 클라이언트로 전송
서버 프로그램
서버 프로그램에서 사용해야할 함수와 순서는 아래와 같습니다.
우선 socket 부터 만들어야 합니다. TCP/IP에서는 SOCK_STREAM을 UDP/IP에서는 SOCK_DGRAM을 사용하는 것을 참고하여 주십시오. socket()에 대한 더 자세한 말씀은 "Unix C Reference의 11장 7절 소켓 열고 닫기"를 참고하십시오.bind() 함수를 이용하여 socket에 server socket 에 필요한 정보를 할당하고 커널에 등록int server_socket;
server_socket = socket( PF_INET, SOCK_STREAM, 0);
if (-1 == server_socket)
{
printf( "server socket 생성 실패");
exit( 1) ;
}
- 만들어진 server_socket 은 단지 socket 디스크립터일 뿐입니다.
- 이 socket에 주소를 할당하고 port 번호를 할당해서 커널에 등록해야 합니다.
- 커널에 등록해야 다른 시스템과 통신할 수 있는 상태가 됩니다.
- 더 정확히 말씀드린다면 커널이 socket 을 이용하여 외부로부터의 자료를 수신할 수 있게 됩니다.
- socket에 주소와 port 를 할당하기 위해 sockaddr_in 구조체를 이용합니다.
- htonl( INADDR_ANY) 는 주소를 지정해 주는 것으로 inet_addr( "내 시스템의 IP ")로도 지정할 수 있습니다. 그러나 프로그램이 실행되는 시스템 마다 IP 가 다를 것이므로 주소 지정을 고정 IP로 하지 않고 htonl( INADDR_ANY) 를 사용하는 것이 편리합니다.
struct sockaddr_in server_addr;
memset( &server_addr, 0, sizeof( server_addr);
server_addr.sin_family = PF_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);
}
if( -1 == listen( server_socket, 5))
{
printf( "대기상태 모드 설정 실패n");
exit( 1);
}
- listen() 함수를 호출하면 클라이언트의 접속 요청이 올 때 까지 대기 상태가 됩니다. 즉, 블록된 모습이 되죠.
- 함수가 리턴이 되었을 때에는 클라이언트의 접속이 요청 되었다든지, 아니면 에러가 발생했을 경우입니다.
- 에러 없이 함수가 복귀했다면 클라이언트의 접속 요청입니다.
- 접속 요청을 허락합니다.
- accept()로 접속 요청을 허락하게 되면 클라이언트와 통신을 하기 위해서 커널이 자동으로 소켓을 생성합니다.
- 이 소켓을 client socket이라고 하겠습니다.
- client socket 정보를 구하기 위해 변수를 선언합니다. 그리고 client 주소 크기를 대입합니다.
- accept()를 호출 후에 에러가 없으면 커널이 생성한 client socket 을 반환해 줍니다.
int client_addr_size;
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);
- read() 를 이용하여 클라이언트로부터 전송된 자료를 읽어 들입니다.
- 만일 클라이언트로부터 전송된 자료가 없다면 송신할 때 까지 대기하게 됩니다. 즉, 블록된 모습이 됩니다.
- 수신된 데이터의 길이를 구하여 전송 데이터를 준비합니다.
- write() 를 이용하여 클라이언트로 자료를 송신합니다.
write( client_socket, buff_snd, strlen( buff_snd)+1); // +1: NULL까지 포함해서 전송
sprintf( buff_snd, "%d : %s", strlen( buff_rcv), buff_rcv);
close( client_socket);
클라이언트 프로그램
클라이언트 프로그램은 서버에 비해 간단합니다. 바로 설명 들어갑니다.
socket() 을 이용하여 소켓을 먼저 생성합니다.connect()를 이용하여 서버로 접속을 시도합니다.int client_socket;
client_socket = socket( PF_INET, SOCK_STREAM, 0);
if( -1 == client_socket)
{
printf( "socket 생성 실패n");
exit( 1);
}
- 주소 정보에 서버의 주소와 포트번호를 지정하고
- 서버와의 연결을 시도합니다.
- 예제에서는 시스템 자기를 가르키는 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);
}
- 접속에 성공하면 데이터를 전송합니다.
- 자료를 수신하고 화면에 출력합니다.
- socket 을 소멸하여 통신 작업을 완료합니다.
write( client_socket, argv[1], strlen( argv[1])+1); // +1: NULL까지 포함해서 전송
read ( client_socket, buff, BUFF_SIZE);
printf( "%sn", buff);
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); } while( 1) { if( -1 == listen(server_socket, 5)) { printf( "대기상태 모드 설정 실패n"); exit( 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: %sn", 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> #include "sample.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( "%sn", buff); close( client_socket); return 0; }
이 글에 있는 프로그램으로 될까요?
한 PC에서는 웹캠으로 받은 영상 원본을 띄우고, 다른 한쪽에서는 원본 영상을 디코딩 해서 띄우려는데...
아는게 없어서... 질문도 이상하네요..;;