| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- fscanf
- DMA
- sscanf
- 프레임버퍼
- interrupt handler
- 환경 변수
- gparted
- jenkins
- activities
- memcmp
- makefile
- 젠킨스
- sprintf
- intents
- context
- 디스크립터
- ubuntu
- 문자형 디바이스 파일
- Shared Folder
- usb2.0
- interrupt context
- pagefile.sys
- 디스크 축소
- fprintf
- 속도저하
- layouts
- HDR
- 소캣
- context switch
- 멀티프로세싱
- Today
- Total
do{학습}while
소캣 통신이란? 본문
소캣(Socket) 통신이란
네트워크 상에서 두개의 노드가 서로 통신하기 위해 연결하는 방식입니다. 클라이언트 노드가 또 서버 노드와 연결되어 있는 동안, 서버 노드는 IP의 특정 포트에서 수신합니다.
소캣 통신 흐름도

클라이언트단 주요 함수
클라이언트단에서 서버와 데이터를 주고 받기 전 설정을 하기 위한 함수가 존재합니다. socket(), connect()함수가 존재합니다. 연결 설정을 마치고 데이터를 주고 받기 위해 write(), read()함수가 있습니다.
각각의 함수들의 시그니쳐를 살펴보면서 용도와 전달되어야하는 인자를 살펴보겠습니다.
socket()
extern int socket (int __domain, int __type, int __protocol) __THROW;
용도
소캣을 생성하는 함수
파라미터
__domain: 주소 패밀리를 지정합니다. TCP 혹은 UDP를 지정하고 싶은 경우 인자로 AF_INET을 전달합니다.
__type: 소캣의 타입을 지정합니다. SOCK_STREAM(TCP), SOCK_DGRAM(UDP)
__protocol: TCP 혹은 UDP를 사용할 경우 기본 프로토콜(0)을 사용하면 됨
반환값
생성 성공 시 소캣 파일 디스크립터를 반환하고 실패 시 -1을 반환합니다.
htons()
extern uint16_t htons (uint16_t __hostshort)
용도
16비트 정수를 호스트 바이트 순서(x86 아키텍처 기준: little endian)에서 네트워크 바이트 순서(big endian)로 변환해주는 함수
파라미터
__hostshort: big endian으로 변환할 정수값을 전달
반환값
전달 받은 정수(little endian)를 big endian으로 변환한 값을 전달합니다.
예를 들어 정수 8080을 인자로 전달한다면
little endian: 1f 90 -> big endian: 90 1f
으로 변환하여 반환합니다.
inet_pton()
extern int inet_pton (int __af, const char *__restrict __cp, void *__restrict __buf) __THROW;
용도
문자열로 된 IP 주소를 네트워크 바이트 순서(빅 엔디안)로 변환하는 함수
파라미터
__af: 소캣의 파일 디스크립터 전달하기 위한 파라미터
__cp: 문자열로 IP주소를 전달하기 위한 파라미터
__buf: big endian으로 변환한 값을 저장하기 위한 버퍼 전달을 위한 파라미터
반환값
성공 시 1을 반환합니다.
__cp가 올바른 표현이 아닐 경우 0을 반환합니다.
오류가 발생하면 -1을 반환하며, errno 변수에 오류 코드가 설정됩니다.
connect()
extern int connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
용도
소켓 파일 디스크립터를 사용하여 특정 주소에 대한 연결을 설정하는 데 사용하는 함수
파라미터
__fd: 연결할 소켓의 파일 디스크립터를 전달하는 파라미터
__addr: 연결하려는 주소를 가리키는 포인터를 전달하는 파라미터
__len: 주소 구조체의 크기를 전달하는 파라미터입니다.
반환값
성공 시 0을 반환합니다.
실패 시 -1을 반환하며, errno 변수에 오류 코드가 설정됩니다.
send()
extern ssize_t send (int __fd, const void *__buf, size_t __n, int __flags);
용도
데이터를 특정 소켓으로 보내는 데 사용하는 함수
파라미터
__fd: 연결할 소켓의 파일 디스크립터를 전달하는 파라미터
__buf: 전송할 데이터를 위한 파라미터입니다. void 포인터 형식이므로 다양한 타입을 전달할 수 있습니다.
__flags: 주소 구조체의 크기를 전달하는 파라미터입니다.
반환값
성공 시 전송된 바이트 수를 반환합니다.
실패 시 -1을 반환하며, errno를 통해 오류 원인을 알 수 있습니다.
read()
__fortify_function __wur ssize_t read (int __fd, void *__buf, size_t __nbytes)
용도
켓에서 데이터를 읽는 데 사용하는 함수
파라미터
__fd: 연결할 소켓의 파일 디스크립터를 전달하는 파라미터
__buf: 서버로부터 전달 받은 값을 저장할 버퍼
__nbytes: 주소 구조체의 크기를 전달하는 파라미터입니다.
반환값
성공 시 0을 반환합니다.
실패 시 -1을 반환하며, errno 변수에 오류 코드가 설정됩니다.
서버단 주요 함수
서버단에서는 클라이언트와 데이터를 주고 받기 전 크게 소켓을 생성, 소켓과 포트 바인딩, 소켓 연결 대기상태 전환, 소켓의 연결 요청 수락 총 4단계를 거칩니다.
각각의 단계를 수행하기 위한 함수들을 알아보겠습니다.
bind()
extern int bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
용도
소켓에 IP 주소와 포트 번호를 할당하는 함수
파라미터
__fd: 바인딩할 소켓의 파일 디스크립터를 전달하는 파라미터
__addr: 바인딩할 을 저장할 주소 객체를 전달하기 위한 파라미터
__len: 주소 구조체의 크기를 전달하는 파라미터입니다.
반환값
성공 시 0을 반환합니다.
실패 시 -1을 반환하며, errno 변수에 오류 코드가 설정됩니다.
listen()
extern int listen (int __fd, int __n)
용도
서버 소켓을 연결 요청 대기 상태로 설정하는 데 사용하는 함수
파라미터
__fd: 연결할 소켓의 파일 디스크립터를 전달하는 파라미터
__n: 연결 요청을 저장하기 위한 큐의 길이를 설정
반환값
성공 시 0을 반환합니다.
실패 시 -1을 반환하며, errno 변수에 오류 코드가 설정됩니다.
accept()
extern int accept (int __fd, __SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len);
용도
서버가 클라이언트의 연결 요청을 수락하는 데 사용하는 함수
파라미터
__fd: 연결할 소켓의 파일 디스크립터를 전달하는 파라미터
__addr: 클라이언트의 주소 정보를 저장할 구조체에 대한 포인터
__addr_len: 주소 구조체의 크기를 전달하는 파라미터입니다.
반환값
성공 시 클라이언트와의 새로운 연결을 나타내는 파일 디스크립터를 반환합니다. 이 파일 디스크립터는 클라이언트와의 데이터 통신에 사용됩니다.
실패 시 -1을 반환하며, errno를 통해 오류 원인을 알 수 있습니다.
setsockopt()
extern int setsockopt (int __fd, int __level, int __optname, const void *__optval, socklen_t __optlen);
용도
소캣 옵션을 설정하는 함수
파라미터
__fd: 옵션을 설정할 소켓의 파일 디스크립터를 전달하는 파라미터
__level: 옵션을 레벨을 설정하는 파라미터
__optname: 설정할 옵션의 이름을 전달하는 파라미터
__optval: 서버로부터 전달 받은 값을 저장할 버퍼
__optlen: 주소 구조체의 크기를 전달하는 파라미터입니다.
반환값
성공 시 0을 반환합니다.
실패 시 -1을 반환하며, errno 변수에 오류 코드가 설정됩니다.
서버단 코드
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
typedef struct
{
int pos;
int speed;
}Ball;
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
// char buffer[BUFFER_SIZE] = {0};
Ball ball;
char *hello = "Hello from server";
// 소켓 파일 디스크립터 생성
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 소켓 옵션 설정
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);
// 소켓과 포트를 바인딩
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);
}
read(new_socket, &ball, sizeof(Ball));
printf("Message from client: pos: %d speed: %d\n", ball.pos, ball.speed);
send(new_socket, hello, strlen(hello), 0);
printf("Hello message sent\n");
close(new_socket);
close(server_fd);
return 0;
}
클라이언트단 코드
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
typedef struct
{
int pos;
int speed;
}Ball;
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
char *hello = "Hello from client";
char buffer[BUFFER_SIZE] = {0};
Ball ball = {1,1};
// 소켓 생성(TCP 소캣을 생성)
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);
// 서버 주소(네트워크 바이트 순서) 변환
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, &ball, sizeof(Ball), 0);
printf("Hello message sent\n");
read(sock, buffer, BUFFER_SIZE);
printf("Message from server: %s\n", buffer);
close(sock);
return 0;
}
Reference
https://www.geeksforgeeks.org/socket-programming-cc/
Socket Programming in C - GeeksforGeeks
A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.
www.geeksforgeeks.org
'C & C++' 카테고리의 다른 글
| Trouble shooting) 스레드 동기화 과정 중 오류 (0) | 2024.05.23 |
|---|