Linux/Linux_programing

Socket - 02. Server socket

sosal 2009. 10. 3. 00:52
반응형

/*
 http://sosal.tistory.com/
 * made by so_Sal
 */

서버 소켓 함수들

#include<sys/socket.h>

int socket( int __domain, int __type, int __protocol);
int bind(int socket, const struct sockaddr *address, size_t address_len);
int listen(int socket, int backlog);
int accept(int socket,struct sockaddr *address, size_t address_len);
int connect(int socket, const struct sockaddr *address, size_t address_len);

:: socket :: linux programing 소켓의 첫 글을 참조하세요.


:: bind :: // 소켓에 이름 붙이기.
int bind(int socket, const struct sockaddr *address, size_t address_len);
    //소켓      //주소         //주소의 길이

socket을 다른 프로세스들이 사용 할 수 있게 하려면,
소켓에 정보들이 있어야 합니다.
마치 집에서 다른집으로 전화를 할때 전화번호를 알아야 전화할 수 있는것 처럼.

AF_UNIX :: 유닉스 내부 네트워크 시스템 소켓 :: 주소가 곧 *경로*
AF_INET :: 유닉스 외부 네트워크 시스템 소켓 :: IP, Port가 주소이다.


내부 네트워크 AF_UNIX 도메인 에서는, 소켓의 위치를 알아야 통신이 가능합니다.
(서버에서 만든 소켓이 프로세들의 통신을 가능하게 해줌.)

외부 인터넷 네트워크 AF_INET 도메인 에서는,
학교의 이름(IP)과 반의 위치(port)를 알아야 반에 찾아갈 수 있겠죠.

bind :: 소켓과 주소를 합치는 함수
소켓 1번글 01. socket(), sockaddr 에 대한 글에서 sockaddr을 참조하세요.
socket()로 생성한 소켓과 sockaddr 구조체를 합쳐주는 역할을 하는것이 bind()
소켓에 주소를 연결 한다면, 클라이언트 프로세스가 소켓을 찾아갈 수 있을 것.
물론 이때의 소켓은 서버 소켓이고, 주소 역시 서버소켓의 구조체입니다.

:: listen :: // 소켓의 귓구멍을 열어놓기
int listen(int socket, int backlog);
    //소켓   //소켓 연결요청 대기열

일단 누구와 이야기 하기 위해선 귀가 있어야 함.
listen 함수가 귀를 여는 역할을 한다.
전화를 예로 들자면, 전화선을 꼽는것.
소켓 연결요청 대기열은 접속 연결시도가 들어올 수 있는 최대 갯수를 말한다.
보통 5를 많이 사용함..

:: accept :: // 상대가 말을 걸면 대화를 받아줌
listen 함수에서 귀를 뚫었다면, 나에게 대화를 건 상대를 받아 주기만 하면 되겠다.
누군가가 전화를 걸면 받는 행위라고 생각하면 될듯 합니다.
하지만 대화를 거는 상대가 없다면, 기다려야겠지요?

이 함수는 상대방이 연결을 시도할 것을 기다립니다.
accept에서 2번째 인자 sockaddr은 상대방의 주소를 나타내는 구조체입니다.
상대방이 내 소켓에 연결하여 던져준 내용이
누가 줬는지 기억해야만 답장을 보낼 수 있겠지요..!?

accept 함수는 연결요청이 있다면, 프로세스의 실행이 재개되고,
그 소켓 연결 요청을 수락했을때, 소켓 서술자를 반환하게 됩니다.

소켓 연결 대기열 backlog에 연결 요청이 하나도 없다면 호출이 차단됩니다.
위 차단 특성은 O_NONBLOCK 플래그를 설정함으로 써 변경 할 수 있습니다.

fcnt 계열의 함수를 사용.
int falgs = fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, O_NONBLOCK | flags);

자세한 fcntl에 대한 내용은 생략하겠습니다. ㅠㅠ
예제); 아래 예제는 바로 다음 client socket 글의 예제와 연결되는 예제입니다.
물론 AF_UNIX도메인과 AF_INET 도메인으로 따로 나뉘어 집니다.
모두 내부에서 소켓을 이용하여 통신하는 프로그램들 이지만,
인터넷 프로토콜 AF_INET 또한 내부에서 통신이 가능하므로
둘다 예제를 실험해 보세요~~^-^


====== AF_INET 외부 인터넷 네트워크 도메인 server.c =======

/* 열혈강의 윤성우저자의 소스입니다.
 * helloworld_server.c
 * Written by SW. YOON
 */

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

void error_handling(char *message);

int main(int argc, char *argv[])
{
 int serv_sock;
 int clnt_sock;
 struct sockaddr_in serv_addr;
 struct sockaddr_in clnt_addr;
 int clnt_addr_size;
 char message[]="Hello World!\n";
 
 if(argc!=2){
  printf("Usage : %s <port>\n", argv[0]);
  exit(1);
 }
 
 serv_sock=socket(PF_INET, SOCK_STREAM, 0); /* 서버 소켓 생성 */
 if(serv_sock == -1)
  error_handling("socket() error");
 
 memset(&serv_addr, 0, sizeof(serv_addr));
 serv_addr.sin_family=AF_INET;
 serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
 serv_addr.sin_port=htons(atoi(argv[1]));
 
 if( bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr))==-1 ) /* 소켓에 주소 할당 */
  error_handling("bind() error");
 
 if( listen(serv_sock, 5)==-1 )  /* 연결 요청 대기 상태로 진입 */
  error_handling("listen() error");
 
 clnt_addr_size=sizeof(clnt_addr); 
 clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr,&clnt_addr_size); /* 연결 요청 수락 */
 if(clnt_sock==-1)
  error_handling("accept() error"); 
 
 write(clnt_sock, message, sizeof(message)); /* 데이터 전송 */ 
 close(clnt_sock); /* 연결 종료 */
 return 0;
}

void error_handling(char *message)
{
 fputs(message, stderr);
 fputc('\n', stderr);
 exit(1);
}

===== AF_UNIX 내부 네트워크 도메인 server.c =====

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/un.h>

int
main(){
        int server_sockfd, client_sockfd;
        int server_len, client_len;

        struct sockaddr_un server_address;
        struct sockaddr_un client_address;

        unlink("server_socket");
//현재 위치에 server_socket이라는 파일을 만드는데,
//그와 똑같은 이름이 있다면 없애야겠습니다. 그 함수입니다.

        server_sockfd = socket(AF_UNIX, SOCK_STREAM,0);
        server_address.sun_family = AF_UNIX;
        strcpy(server_address.sun_path, "01.server_socket");
        server_len = sizeof(server_address);
        bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
//주소구조체를 만들어서 소켓과 합침으로써 소켓에 주소가 생겼습니다.

        listen(server_sockfd, 5);
//전화를 받을 수 있는 상태를 만드는 listen입니다. 아래 accept에서 기다리겠지요.

        while(1){
                char ch;
                printf("server waiting \n");
                client_len = sizeof(client_address);
                client_sockfd = accept(server_sockfd,
                          (struct sockaddr *)&client_address,&client_len);
                read(client_sockfd, &ch, 1);
                ch++;
                write(client_sockfd, &ch, 1);
                close(client_sockfd);
        }
}

Socket 게시물들은
begining Linux programing.
Linux 언쉬리드' 를 참고하였습니다.


 


'Linux > Linux_programing' 카테고리의 다른 글

System - 01. Process 개념  (0) 2009.10.07
Socket - 03. Client socket  (2) 2009.10.03
리눅스 Socket - socket(), sockaddr  (0) 2009.09.28
리눅스 FILE - open(), close() 시스템콜  (1) 2009.09.28
리눅스 FILE - read() 시스템콜  (1) 2009.09.27