소켓(Socket)

 

프로세스간 상호 양방향 통신 방식

- 각 호스트 간의 통신 시 구축되는 물리적인 연결 종단점

- 파일 처리 방식으로 다룰 수 있는 기술자(Descriptor) 제공

- 각 종단점으로써 여러 속성을 보유

 

네트워크를 통한 통신 가능

- TCP/IP에 대한 인터페이스 제공

 

소켓을 통한 프로세스 통신은 클라이언트/서버 모델에 기초

 

소켓의 유형

Stream Socket

- 연결 지항형 (TCP 기반)

- 소켓 간의 연결 후 데이터 전송

- 일상 생활의 전화 개념과 유사

 

Datagram Socket

- 비 연결형 (UDP 기반)

- 송수신 시 도착지 주소 필수

- 일상 생활의 편지 개념과 유사

 

Raw Socket

- 저 수준 프로토콜 액세스

- ICMP, OSPF 등이 사용

- IP 계층 이용

 

소켓 연결 과정

1. 서버가 명명된 소켓을 생성

2. 클라이언트가 명명되지 않은 소켓을 생성하고, 연결을 요청

3. 클라이언트가 연결됨. 서버는 원래 명명된 소켓을 유지

 

소켓 생성

소켓 사용시 아래의 파일 포함

#include <sys/types.h>

#include <sys/socket.h>

 

소켓의 함수

socket() : 사용하고자 하는 통신 프로토콜을 지정

- int socket(int domain, int type, int protocol);

 

socketpair() : 소켓 연결의 한 쌍을 지정

- int socketpair(int domain, int type, int protocol, int sv[2]);

 

close() : 소켓의 연결을 종료, int close(int fd);

shutdown() : 선택적 소켓의 연결을 종료 int close(int fd, int option);

 

bind() : 소켓에 이름을 결합

- int bind(int sockfd, sockaddr * myaddr, int addrlen);

 

listen() : 서버 프로세스가 통신할 연결 기반 소켓 설정

- int listen(int sockfd, int size);

 

accept() :  서버 프로세스에서 클라이언트 소켓과 연결을 설정 하기 위해 호출

- int accept(int sockfd, struct sockaddr *peer, int *addrlen);

 

connect() : 클라이언트가 서버에 연결을 요청하기 위해 호출

- int connect(int socfd, strcut sockaddr *servaddr, int addrlen);

 

write() : 다른 소켓에 메시지 전송

- ssize_t write(int fd, const void *buf, size_t count);

 

read() : 다른 소켓에서 메시지 수신

- ssize_t read(int fd, void *buf, size_t count);

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//--------------------------------------------------------------
// daytime_server_v01.c
// 현재 시각을 클라이언트에 반환
// 사용: daytime_server 13
//--------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <arpa/inet.h>
#define MAXLINE 80
int main(int argc, char const *argv[])
{
    /* code */
    int listenfd, connfd;
    //1. servaddr clnt addr
    struct sockaddr_in servaddr;
    struct sockaddr_in clntaddr;
    char buff[MAXLINE];
    time_t ticks;
    if (argc != 2)
    {
        fprintf(stderr, "usage: %s <port>\n", argv[0]);
        exit(0);
    }
    // 2. server socket
    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        fprintf(stderr, "socket() error\n");
        exit(EXIT_FAILURE);
    }
    // 3. initialize serv_addr by 0
    memset(&servaddr, 0sizeof servaddr);
    // 4. AF_INET
    servaddr.sin_family = AF_INET;
    // 5. 13 port to Network bytes
    servaddr.sin_port = htons(atoi(argv[1])); //13
                                              // 6. INADDR_ANY
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    // 7. bind()
    if ((bind(listenfd, (struct sockaddr *)&servaddr, sizeof
        servaddr)) < 0)
    {
        fprintf(stderr, "bind() error\n");
        exit(EXIT_FAILURE);
    }
    if (listen(listenfd, 5== -1)
    { // 연결 요청 대기 상태로 진입
        fprintf(stderr, "listen() error\n");
        exit(EXIT_FAILURE);
    }
    for (;;)
    {
        puts("서버가 연결요청을 기다림..");
        socklen_t clntaddr_len = sizeof(clntaddr);
        if ((connfd = accept(listenfd, (struct sockaddr
            *)&clntaddr, &clntaddr_len)) < 0)
        {
            fprintf(stderr, "accept() error\n");
            exit(EXIT_FAILURE);
        }
        ticks = time(NULL);
        // 클라이어트 주소/이름 정보를 출력한다.
        memset(buff, 0x00, MAXLINE);
        inet_ntop(AF_INET, &clntaddr.sin_addr.s_addr, buff, sizeof
            buff);
        printf("클라이언트가 연결됨: IP: %s(%d)\n", buff,
            ntohs(clntaddr.sin_port));
        //puts("클라이언트가 연결됨..");
        memset(buff, 0x00, MAXLINE);
        snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
        if ((write(connfd, buff, MAXLINE)) <= 0)
        {
            fprintf(stderr, "write() error\n");
            close(connfd);
        }
        close(connfd);
    }
    close(listenfd);
    return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4f; text-decoration:none">Colored by Color Scripter
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none; color:white">cs

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//--------------------------------------------------------------
// daytime_client.c
// daytime 서비스를 요청하는 TCP클라이언트
// ex) daytime_client 129.6.15.28
//--------------------------------------------------------------
#include <arpa/inet.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#define MAXLINE 80
int main(int argc, char *argv[])
{
    int sockfd, n;
    char buf[MAXLINE + 1];
    // 1. 서버 주소용 구조체: sockaddr_in
    struct sockaddr_in serv_addr;
    if (argc != 2)
    {
        printf("usage: daytime_client <IP_ADDRESS>\n");
        exit(EXIT_SUCCESS);
    }
    // 2. socket()
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        fprintf(stderr, "socket() error");
        exit(EXIT_FAILURE);
    }
    // 3. initialize serv_addr by 0
    // bzero(&serv_addr, sizeof serv_addr);
    memset(&serv_addr, 0sizeof serv_addr);
    // 4. AF_INET
    serv_addr.sin_family = AF_INET;
    // 5. 13 port to Network bytes
    serv_addr.sin_port = htons(13); /* daytime port */
                                    // 6. IP문자열 serv_addr.sin_addr
    if ((inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)) <= 0)
    {
        fprintf(stderr, "inet_pton error for %s", argv[1]);
        exit(EXIT_FAILURE);
    }
    // 7. connect()
    if (connect(sockfd, (struct sockaddr_in *)&serv_addr, sizeof
        serv_addr) < 0)
    {
        fprintf(stderr, "Can't connect to server", argv[1]);
        exit(EXIT_FAILURE);
    }
    // 8. read()
    if ((n = read(sockfd, buf, MAXLINE)) < 0)
    {
        fprintf(stderr, "fputc() error");
        exit(EXIT_FAILURE);
    }
    buf[n] = 0// null terminate
    printf("%s", buf);
    close(sockfd);
    return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4f; text-decoration:none">Colored by Color Scripter
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none; color:white">cs

 

 

 

서버쪽 함수

서버(Server)의 구조

1. 서버에서 사용하는 구조체 초기화

2. 서버 소켓 생성 및 클라이언트 대기

3. select를 이용한 접속 상황 관리, 클라이언트가 접속하면 소켓기술자의 상태가 변화하여 접속 여부 확인

4. 접속처리, 접속 한 클라이언트가 넘겨주는 정보로 서버의 각 구조체를 업데이트

5. 데이터 송수신

-클라이언트로 받은 데이터는 검색하여 같은 채팅 방 안에 접속한 각각의 다른 클라이언트에게 전송

-데이터 수정 작업 필요(이름 첨가 등)

6. 서버 소켓 닫기, 종료 하지 않는 다면 3으로 복귀

7. 프로그램 종료

 

소켓 생성

socket()을 사용하여 생성

동작 System call: int socket(int domain, int type, int protocol)

 

소켓 구조체

도메인 (domain), 서버와 클라이언트 소켓이 존재하는 장소를 지칭

유형 (type), 클라이언트와 서버 사이에 존재할 수 있는 통신 유형 결정

프로토콜(protocol), 소켓 유형을 구현하는 저급의 수단을 명시

 

소켓 : 패밀리

지원하는 프로토콜 그룹 중에서 사용하려는 소켓이 적용될 프로토콜을 선택

프로토콜- 여러 소켓 형태를 제공하는 경우 사용, 기본 값은 0

 

소켓 : 형식 (Type)

Generic Type과 Protocol-Specific Type으로 구분

- Socket 인터페이스 구현시 C언어에 void 타입이 없었음

- 연결 지향형과 비 연결형, 저수준 소켓 프로토콜 제어형

 

저수준 프로토콜

- IP 프로토콜과같은 레벨에 있는 프로토콜을 사용시 필요 ex)ICMP (Internet Control Message Protocol)

- TCP/UDP 보다 하위 계층으로 사용이 까다로운 반면 직접적인 제어가 가능

 

주소 지정

클라이언트는 일반적으로 주소를 바인딩 하지 않는다.

- 클라이언트가 서버와의 통신을 시도할 때 커널이 자동으로 지정

- 서버와 통신하는 동안만 주소가 유효(임시적 주소)

 

서버는 일반적으로 스스로 주소를 지정 작업 수행(고정 주소)

 

IP 주소와 포트번호

Server에 접속하기 위해 필요한 것, IP 주소(address), 포트 번호(port number)

포트번호

-TCP/IP 프로토콜은 주어진 호스트 컴퓨터 내에서 여러 곳의 목적지로 데이터를 전송하기 위하여 서로 다른 포트를 사용

- 한 클라이언트 컴퓨터가 특정 어플리케이션을 사용하기 위하여 호스트에 연결 할 경우, 그 어플리케이션에 접속할 포트가 사용

- 포트 번호를 사용하는 이유: 동시에 한 개의 IP주소로 여러 클라이언트가 접속 가능

 

소켓 네이밍

서버가 명명되지 않은 소켓 생성시, bind()를 사용하여 이름 부여

System call: int bind(int fd, struct sockaddr* address, int addressLen)

-addressLen는 주소 구조체의 길이를 포함

-입력될 주소의 유형과 값은 소켓 도메인에 의함

 

기본 자료형

sockaddr 구조체

-기본 적인 소켓 주소 구조체, 호환성을 위해 존재

-변수: 구조체의 크기, Family Type, 소켓의 주소 데이터

 

sockaddr_in 구조체

-IPv4 소켓 주소 구조체

-주소를 담기 위해 in_addr 구조체 사용

-변수 : 구조체의 크기, Family Type, 소켓의 주소 및 포트 번호

 

sockaddr_un 구조체: 유닉스 호스트 상의 통신

-유닉스 소켓 주소 구조체

-동일 호스트에서의 통신이 일반 TCP통신 보다 두 배 빠름

-변수: 소켓 상수, 호스트 경로

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
 
int main(int argc, char *argv[])
{
    struct addrinfo hints, *res, *p;
    int status;
 
    char ipstr[INET6_ADDRSTRLEN];
 
    if (argc != 2)
    {
        printf("usage : showip hostname\n");
        return -1;
    }
 
    memset(&hints, 0sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
 
    if ((status = getaddrinfo(argv[1], NULL&hints, &res)) != 0)
    {
        perror("getaddrinfo");
        return -1;
    }
 
    printf("IP addresses for %s:\n\n", argv[1]);
 
    for (p = res; p != NULL; p = p->ai_next)
    {
        void *addr;
        char *ipver;
        if (p->ai_family == AF_INET)
        {
            struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
            addr = &(ipv4->sin_addr);
            ipver = "IPv4";
        }
        else
        {
            struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
            addr = &(ipv6->sin6_addr);
            ipver = "IPv6";
        }
        inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
        printf(" %s: %s\n", ipver, ipstr);
 
    }
 
    freeaddrinfo(res);
 
    return 0;
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4f; text-decoration:none">Colored by Color Scripter
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none; color:white">cs

+ Recent posts