본 내용은 한양대학교 이석복 교수님의 강의를 참고하여 정리하였습니다. 교재는 Pearson/Addison Wesley에서 출판한 Computer networking : a top-down approach입니다.
Socket
- 두 프로그램이 네트워크를 통해 서로 통신을 수행할 수 있도록 양쪽에 생성되는 인터페이스
- 주로 TCP 기반 소켓과 UDP 기반 소켓을 사용
동작
- Server의 socket() : 소켓을 생성
- Server의 bind() : 생성된 소켓에 IP address와 port 번호를 묶음
- Server의 listen() : 서버는 클라이언트에서 연결 요청이 올 때까지 대기
- Server의 accept() : 미결정 큐에 있던 연결 요청을 꺼내서 연결 생성
- Server의 send()/recv() : 데이터 송수신
- Server의 close() : 소켓 연결을 해제
- Client의 socket() : 소켓을 생성
- Client의 connect() : 서버와 연결하기 위해 요청
- Client의 send()/recv() : 데이터 송수신
- Client의 close() : 소켓 연결을 해제
- Cline는 임의의 port 번호를 사용해도 되기 때문에 bind() 없어도 됨
구현 (C)
- socket()
1
|
int socket(int domain, int type, int protocol)
|
cs |
* 소켓 생성
* Return : file descriptor / -1
* domain
+ PF_INET : IPv4 (일반적으로 사용)
+ AF_INET6 : IPv6
* type
+ SOCK_STREAM : TCP 통신용
+ SOCK_DGRAM : UDP
* protocol
+ IP 프로토콜 값으로 일반적으로 0으로 설정
- bind()
1
|
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
cs |
* 생성된 소켓에 IP address와 port 번호를 묶음
* Return : 0 / -1
* sockfd : socket file descripter
* addr : IP address와 port 번호를 포함하는 구조체
* addrlen : 주소 구조체의 길이
- listen()
1
|
int listen(int sockfd, int backlog)
|
cs |
* 서버는 클라이언트에서 연결 요청이 올 때까지 대기
* Return : 0 / -1
* sockfd : socket file descripter
* backlog : 연결 요청들을 대기시키는 queue의 최대 길이. 만약에, queue가 모두 차있는 상태에서 연결 요청이 온다면, 클라이언트는 'ECONNREFUSED'라는 에러 메시지를 받음
- accept()
1
|
int new_socket = accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
|
cs |
* 대기 큐에서 요청을 꺼내어 연결 생성
* Return : 새로운 소켓 지정 번호 생성 / -1
* addr : 클라이언트의 IP address와 port 번호
* addrlen : 주소 구조체의 길이
- connect()
1
|
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
cs |
* 서버와 연결하기 위해 요청
* Return : 0 / -1
* addr : 서버의 IP address와 port 번호를 포함하는 구조체
* addrlen : 주소 구조체의 길이
- 주소 구조체
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
struct sockaddr {
u_short sa_family;
char sa_data[14];
};
struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
struct in_addr {
__u32 s_addr;
};
|
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
63
64
65
66
67
68
69
70
71
72
73
|
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 8080
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};
char *hello = "Hello from server";
// socket file descriptor 생성
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
// socket을 port 8080에 붙이기
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
&opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
// socket을 port 8080에 붙이기
if (bind(server_fd, (struct sockaddr *)&address,
sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
// 요청 대기
if (listen(server_fd, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
// 연결 승인
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
// 읽기
valread = read( new_socket , buffer, 1024);
printf("%s\n",buffer );
// 데이터 보내기
send(new_socket , hello , strlen(hello) , 0 );
printf("Hello message sent\n");
return 0;
}
|
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
|
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#define PORT 8080
int main(int argc, char const *argv[])
{
int sock = 0, valread;
struct sockaddr_in serv_addr;
char *hello = "Hello from client";
char buffer[1024] = {0};
// socket file descriptor 생성
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// Convert IPv4 and IPv6 addresses from text to binary form
if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)
{
printf("\nInvalid address/ Address not supported \n");
return -1;
}
// 연결 요청
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}
send(sock , hello , strlen(hello) , 0 );
printf("Hello message sent\n");
valread = read( sock , buffer, 1024);
printf("%s\n",buffer );
return 0;
}
|
cs |
참조
- 블로그 1
- 블로그 2
- 블로그 3
'Software Courses > Network' 카테고리의 다른 글
Transport : UDP (0) | 2020.12.31 |
---|---|
Transport : Multiplexing, Demultiplexing (0) | 2020.12.31 |
Application : DNS (0) | 2020.12.30 |
Application : Proxy server (0) | 2020.12.30 |
Application : HTTP (0) | 2020.12.29 |