소켓(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, 0, sizeof 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, 0, sizeof 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, 0, sizeof 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 |
'딥러닝 기반 영상인식 개발 전문가 과정 > 리눅스' 카테고리의 다른 글
6월 5일 메시지큐, 세마포어, 공유메모리 (0) | 2019.06.05 |
---|---|
6월 5일 Thread, 임계영역, Mutex (0) | 2019.06.05 |
6월 4일 ncurses, pipe, fifo (0) | 2019.06.04 |
6월 4일 kill, raise, sigprocmask (0) | 2019.06.04 |
6월 4일 오전 실습 (0) | 2019.06.04 |