๐ก ๋ณธ ๋ฌธ์๋ 'C/C++์์ ํ๋ก์ธ์ค ๊ฐ ํต์ '์ ๋ํด ์ ๋ฆฌํด๋์ ๊ธ์ ๋๋ค.
ํ๋ก์ธ์ค ๊ฐ ํต์ ์ ip๋ก ํต์ ํ๋ ๊ฒ๋ณด๋ค ๋น ๋ฅธ ์ผ๋ จ์ ๊ณผ์ ์ ํตํด ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฃผ๊ณ ๋ฐ๊ณ ์์ต๋๋ค. ์ด ๋ฐฉ๋ฒ ์ค ์ผ๋ถ์ ๋ํด ์ ๋ฆฌํ์์ผ๋ ์ฐธ๊ณ ํ์๊ธฐ ๋ฐ๋๋๋ค.
1. ์๊ฐ
๋ง์ ์ฌ๋๋ค์ด ๋ฌด๊ฑฐ์ด ์์ ์ ๋ถ๋ฆฌํ๊ณ ์ถ๊ฐ ์ต์ ํ, ๋ง์ ๋ ๋ฆฝ์ฑ์ ์ ๊ณตํ ์ ์๊ธฐ ๋๋ฌธ์ ํ๋ก๊ทธ๋จ์ ์ํด ์ค๋ ๋๋ณด๋ค ํ๋ก์ธ์ค๋ฅผ ์ ํํฉ๋๋ค. ์๋ก ๋ค์ด, Google ํฌ๋กฌ ๋ธ๋ผ์ฐ์ ์์ ๊ฐ ํญ์ ์คํํ๊ธฐ ์ํด์ ๋ฌด๊ฑฐ์ด ์ฒ๋ฆฌ(์: ์๋ฒ์์ ํต์ , ๋คํธ์ํฌ ๋ฆฌ์์ค ๊ด๋ฆฌ, ๋ ๋๋ง ๋ฑ)์ ํด์ผํ๋ฉฐ, ๊ฐ ํญ์ ๋งค์ฐ ๋ ๋ฆฝ์ ์ผ๋ก ์๋ํ๊ธฐ์ ์ด๋ ํ๋ก์ธ์ค๋ฅผ ์ฌ์ฉํ๋๋ก ์๋ํฉ๋๋ค. ๋ฐ๋ผ์ ํ๋ ํ๋ก์ธ์ค ์ฃฝ๋๋ผ๋ ๋ค๋ฅธ ํ๋ก์ธ์ค์๋ ์ํฅ์ ์ฃผ์ง ์์ต๋๋ค. ๋ํ ์ด ์ค๊ณ๋ฅผ ํตํด ๋นํ์ฑ ํญ์ ์ด์ ์ฒด์ ์์ ์ฐ์ ์์๊ฐ ๋ฎ์ ์์ ์ผ๋ก ์ฒ๋ฆฌ๋๊ณ ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋ถ์กฑํ ๋ ๋์คํฌ๋ก ์ค์๋๊ณ ๋ค๋ฅธ ํ๋ก์ธ์ค๋ฅผ ์ํด ์ ์ฅ๋๊ธฐ ๋๋ฌธ์ ๋ฉ๋ชจ๋ฆฌ ์ต์ ํ๋ฅผ ๋ ์งํํ ์ ์์ต๋๋ค.
๊ณ์ฐ ์๋์ ํจ์จ์ฑ์ ๋์ด๊ธฐ ์ํด ํ๋ก์ธ์ค๊ฐ ํ๋ ฅํด์ผ ํ๋ ์ํฉ์ด ๋ง์ด ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ ๋ฆฝ์ ์ธ ๋ฉ๋ชจ๋ฆฌ์์ ์คํ๋๋๋ก ์ค๊ณ๋์๊ธฐ ๋๋ฌธ์ ์์คํ ์์ ์ ๊ณตํ๋ ํน๋ณํ ํต์ ๋ฉ์ปค๋์ฆ์ด ํ์ํ๋ฉฐ, ํด๋น ํฌ์คํ์์๋ Shared Memory, Named Pipe, UNIX Domain Socket(TCP/IP ์์ผ๊ณผ ๋ค๋ฆ)์ ์ธ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ ์ํฉ๋๋ค.
2. ํ๋ก์ธ์ค ๊ฐ ํต์
๋จผ์ ๊ฐ ๋ฐฉ๋ฒ์ ์ฅ๋จ์ ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Shared Memory | Named pipe (FIFO) | UNIX domain socket | |
Asyn/Syn | Asynchronous | Synchronous (for unidirectial pipe) | Synchronous |
Size | Data size limit to the physical memory | Queue size is at 16 pages (4096 bytes per page). No limit on data size as long as the data is consumed fast enough | Extremely high throughput. Limit to the speed of the storage device. |
Communication | Multiple processes can access at the same time but synchronization management needed | Unidirectional communication for a single pipe | Bi-directional communication |
Access | Random access | Read-write in a linear fashion | Read-write in a linear fashion |
Memory Manage | Manual memory management | Auto memory mamangement | Auto memory management |
์์ ๋์ด๋ ์ธ ๊ฐ์ง ๊ธฐ์ ์์ Shared Memory๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ๊ฒ์ ๊ด๋ฆฌํด์ผ ํ๊ธฐ ๋๋ฌธ์ ๊ฐ์ฅ ๋ฎ์ ์์ค์ ์ ๊ทผ ๋ฐฉ์์ธ ๋ฐ๋ฉด, UNIX Domain Socket์ ํ๋ก์ธ์ค ๊ฐ์ ์ ์ ํ ํต์ ์ฑ๋์ ์ฝ๊ฒ ์ค์ ํ ์ ์์ต๋๋ค. ํ์ง๋ง ํธ๋ฆฌํจ์๋ ํญ์ ๋น์ฉ์ด ๋ฐ๋ฅด๋ฉฐ, ๋ฐ๋ฉด์ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ๋ ๋ชจ๋ ๋ชฉ์ ์ ๋ง๊ฒ ๋ฐ์ดํฐ ์ ์ก bit์ ์ต์ ํํ ์ ์๋ ์ ์ฐ์ฑ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฅผ ํตํด ๋ฉ๋ชจ๋ฆฌ ์ฉ๋์ ์ต๋ํ ํ์ฉํ๊ณ ์ฌ๋ฌ ํ๋ก์ธ์ค์ ๋์(concurrent) ์ก์ธ์ค๋ฅผ ๊ด๋ฆฌํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ๋ชฉ์ ๊ณผ ๋ฆฌ์์ค์ ๋ฐ๋ผ ์ต์ ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์๊ธฐ ๋ฐ๋๋๋ค.
์ด์ ๊ฐ๋จํ ์์ ๋ฅผ ํตํด ๊ฐ ๋ฐฉ๋ฒ์ ๋ํด ์์ธํ ์ดํด๋ณด๊ฒ ์ต๋๋ค. (์ฐธ๊ณ : ์ฌ๊ธฐ์ ์ฌ์ฉ๋ ์์ ๋ Linux ํ๋ซํผ๋ง ๋์์ผ๋ก ํ๋ฉฐ ์ผ๋ถ ์์ ์ ๋ค๋ฅธ ํ๋ซํผ์์ ์คํํด์ผ ํจ).
2.1 Shared Memory(์ดํ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ)
๊ณต์ ๋ฉ๋ชจ๋ฆฌ๋ ์ฌ์ฉ ๊ฐ๋ฅํ IPC ๊ธฐ์ ์ค ๊ฐ์ฅ ๋น ๋ฆ ๋๋ค. ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ๊ณต์ ํ๋ ํ๋ก์ธ์ค์ ์ฃผ์ ๊ณต๊ฐ์ ๋งคํ๋๋ฉด ํ๋ก์ธ์ค ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ ๋ ์ปค๋์ด ๊ด์ฌํ์ง ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ์์ญ์์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ ๊ฐ์ ธ์ฌ ๋ ํ๋ก์ธ์ค ๊ฐ ์ผ๋ถ ํํ์ ๋๊ธฐํ(e.g. mutexes, condition variables, read-write locks, record locks, semaphores)๊ฐ ํ์ํฉ๋๋ค. ๋จ์ํ๋ฅผ ์ํด ์์ ์์๋ ๋๊ธฐํ ๊ธฐ์ ์ ์ฌ์ฉํ์ง ์์์ต๋๋ค.
๋ค์ ํ๋ก๊ทธ๋จ์ ๋ถ๋ชจ ํ๋ก์ธ์ค์ ์์ ํ๋ก์ธ์ค ์ฌ์ด๋ฅผ ํต๊ณผํ๋ ์นด์ดํฐ๋ฅผ ๋ฐ๋ณต์ ์ผ๋ก ์ฆ๊ฐ์ํค๋ ํ๋ก๊ทธ๋จ์ด๋ฉฐ, ํ๋จ์ ์ผ๋ถ ์ค๋ช ์ ์ฒจ๋ถํ์์ผ๋ ์ฐธ๊ณ ํ์๊ธฐ ๋ฐ๋๋๋ค.
/**
* Sample code for sharing memory between processes
* Two processes will iteratively increase a counter which values stored in a shared memory
*
*/
#include <stdio.h>
#include <unistd.h> // for fork()
#include <sys/mman.h> // for shared memory created
#include <sys/stat.h> // for mode constants
#include <fcntl.h> // for O_* constant
#define SHARED_OBJ_NAME "/somename"
// shared data struct
struct message
{
int pid;
int counter;
};
bool write_message(int pid, int value)
{
int shmFd = shm_open(SHARED_OBJ_NAME, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
ftruncate(shmFd, sizeof(message));
message *msg_ptr = (message*)mmap(NULL, sizeof(message), PROT_READ | PROT_WRITE, MAP_SHARED, shmFd, 0);
printf("Process %d: Increase the counter.\n", pid);
msg_ptr->pid = pid;
msg_ptr->counter = value;
munmap(msg_ptr, sizeof(message));
// remember to close to not hit an error of
// opening too many files
close(shmFd);
return true;
}
bool read_message(int curr_pid, int &curr_value)
{
int shmFd = shm_open(SHARED_OBJ_NAME, O_RDWR, S_IRUSR | S_IWUSR);
ftruncate(shmFd, sizeof(message));
message *msg_ptr = (message*)mmap(NULL, sizeof(message), PROT_READ | PROT_WRITE, MAP_SHARED, shmFd, 0);
if (msg_ptr->pid == curr_pid)
{
printf("Process %d: No new msg available.\n", curr_pid);
return false;
}
else
{
printf("Process %d: Receive %d from PID %d.\n", curr_pid, msg_ptr->counter, msg_ptr->pid);
curr_value = msg_ptr->counter;
munmap(msg_ptr, sizeof(message));
}
close(shmFd);
return true;
}
int main(int argc, char **argv)
{
printf("Init the initial value.\n");
write_message(-1, 0);
// create a child process by calling folk,
// it returns a non-zero pid for parent process and 0 for child process created
pid_t pid = fork();
//--- PARENT PROCESS
if (pid != 0)
{
for (int i = 0; i < 5; i++)
{
int value;
// only write message if reading sucessfully
if (read_message(pid, value))
write_message(pid, ++value);
sleep(0.1);
}
}
//--- CHILD PROCESS
else
{
for (int j = 0; j < 5; j++)
{
int value;
if (read_message(pid, value))
write_message(pid, ++value);
sleep(0.1);
}
}
printf("=========== End of process %d\n", pid);
// shm_unlink(SHARED_OBJ_NAME);
return 0;
}
- fork()๋ ์์ ํ๋ก์ธ์ค๋ฅผ ํ๋ ์ด์์ ํ์ ํ๋ก์ธ์ค๋ก "๋ณต์ "ํ๋ ๋ฐ ์ฌ์ฉ๋๋ฉฐ, ์์ ํ๋ก์ธ์ค pid๋ 0์ผ๋ก ์์ํ๊ธฐ์ PID๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌ๋ถํฉ๋๋ค.
- 'shm_open'์ ํ์ผ ๋์คํฌ๋ฆฝํฐ(OS ์ปค๋์ ์ ์ฅ๋จ)์ ํํ๋ก ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๋ฐ ์ฌ์ฉ๋๋ฉฐ, ์ดํ mmap์ ์ฌ์ฉํ์ฌ ํ๋ก์ธ์ค์ ์ฃผ์ ๊ณต๊ฐ์ ๋งคํํฉ๋๋ค. ๋ฐ๋ผ์ ์ด๋ ์ค์ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ์ ์ฃผ์๋ฅผ ๋ฐํํฉ๋๋ค.
์์ ์ฝ๋๋ ๋ค์์ ์ฌ์ฉํ์ฌ ๋น๋ gccํ๊ณ ์คํํ ์ ์์ต๋๋ค.
gcc shared_memory.cpp -I/usr/local/include/ -L/usr/local/lib -lrt -o shared_mem
./shared_mem
ํ๋ก๊ทธ๋จ์ ์ถ๋ ฅ:
Set the initial value.
Process -1: Increase the counter.
Process 26851: Receive 0 from PID -1.
Process 26851: Increase the counter.
Process 26851: No new msg received
Process 0: Receive 1 from PID 26851.
Process 0: Increase the counter.
Process 26851: No new msg received
Process 26851: Receive 2 from PID 0.
Process 0: No new msg received
Process 26851: Increase the counter.
Process 0: Receive 3 from PID 26851.
Process 0: Increase the counter.
Process 26851: Receive 4 from PID 0.
Process 26851: Increase the counter.
Process 0: Receive 5 from PID 26851.
Process 0: Increase the counter.
=========== End of process 26851
Process 0: No new msg received
=========== End of process 0
์์ ์์ ๋ถ๋ชจ์ ์์ ์ฌ์ด์ ๋ฉ์์ง๊ฐ ์ ๋ฌ๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ํ๋ก์ธ์ค๋ ๊ฐ์ ์ฆ๊ฐ์์ผ ๋ค๋ฅธ ํ๋ก์ธ์ค์ ์ ๋ฌํ๊ณ ๋ค๋ฅธ ํ๋ก์ธ์ค๊ฐ ๊ฐ์ ์ฆ๊ฐ์ํฌ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค. ์ด๋ฌํ ๊ณผ์ ์ ๋ชจ๋ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์์ ๋ฐ์ํฉ๋๋ค.
์ฒ์์ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ํฌ๊ธฐ๊ฐ 0์ด๋ผ๋ ์ ์ ์ฃผ๋ชฉํ ๊ฐ์น๊ฐ ์์ต๋๋ค. 'ftruncate'๋ ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ฅผ ํน์ ๊ธธ์ด๋ก ์๋ฅด๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์ค์ ๋ฐ์ดํฐ ํฌ๊ธฐ๋ณด๋ค ํฐ ๊ฒฝ์ฐ ์ถ๊ฐ ๋ฐ์ดํฐ๋ 0์ผ๋ก ์ด๊ธฐํ๋ฉ๋๋ค.
๊ณต์ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ๋ํ ํฌ์ธํฐ๋ฅผ ์ ๋ฌํ๋ ค๋ ๊ฒฝ์ฐ๊ฐ ์์ฃผ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ฒ์์ ์ธ๊ธํ๋ฏ์ด ํ๋ก์ธ์ค๋ ๋ณ๋์ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ๊ฐ์ง๊ณ ์์ผ๋ฏ๋ก ํ๋ก์ธ์ค ๊ฐ์ ํฌ์ธํฐ๋ฅผ ์ ๋ฌํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํฉ๋๋ค. ์ด ํ๋ก์ธ์ค์ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๋ ๋ค๋ฅธ ํ๋ก์ธ์ค์์๋ ์ ํจํ์ง ์์ต๋๋ค. ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ๋ฐ์ดํธ ๋ฐฐ์ด์ ์ ๋ฌํ๋ ค๋ฉด mmap๋ฅผ ์ฌ์ฉํ์ฌ ์ํ๋ ํฌ๊ธฐ๋ก ์์ญ์ ๋งคํํ ๋ค์, mmap์์ ๋ฐํ๋ ํฌ์ธํฐ ์ฃผ์์ ํฌ๊ธฐ๋ฅผ memcpy์ ์จ์ผ ํฉ๋๋ค. ๊ณต์ ํ๋ ค๋ ๊ตฌ์กฐ์ฒด์ different member types with a data array๊ฐ ์์ ๊ฒฝ์ฐ ์์ผ์ ํตํด ๊ตฌ์กฐ์ฒด๋ฅผ ์ ๋ฌํ ๋ ๋จ์ผ ๋ฐฐ์ด(i.e. a single memory region)๋ก ๊ฒฐํฉ/์ธ์ฝ๋ฉํ์ฌ ์ ๋ฌํด์ผ ํฉ๋๋ค. ๊ทธ๋์ผ ๋ค๋ฅธ ํ๋ก์ธ์ค์์ ์ฝ์ ๋ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ๋ณต์ฌํ๊ณ ๋์ผํ ์์๋ก ๋์ฝ๋ฉํ ์ ์์ต๋๋ค.
2.2 Named pipe(FIFO)
Named pipe(FIFO)๋ ํ์ดํ์ ์ ์ฌํ์ง๋ง ํ์ผ ์์คํ ์ ์ด๋ฆ์ด ์๋ ํน์ ํ์ผ์ ๋๋ค. ํ๋ก์ธ์ค๊ฐ ์ ๋ณด๋ฅผ ๋ณด๋ด๊ณ ๋ค๋ฅธ ํ๋ก์ธ์ค๊ฐ ์ ๋ณด๋ฅผ ๋ฐ๋ ๋ฉ์์ง ์ ๋ฌ์ฒ๋ผ ์ฌ์ฉ๋ฉ๋๋ค. ๋ฐ์ดํฐ๋ ๋์ ์ฒ๋ฆฌ ์๋๋ก ํ์ดํ๋ก ๋ฃ๊ณ ๋บ ์ ์์ต๋๋ค(FIFO). ์ฌ๊ธฐ์ ํ๊ฐ ํ ๋ฒ์ ๋ณด์ ํ ์ ์๋ ์ต๋ ๋ฐ์ดํฐ ํฌ๊ธฐ๋ 16 Pages ๋๋ 65536 Bytes์ ๋๋ค.
/**
* Example for using named pipe for communicating between processes
* This demo is for a unidirectional named pipe which transfer data in one direction
*/
#include <unistd.h> // for fork()
#include <stdio.h> // for printf
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> // for O_* constant
// for print error message
#include <string.h>
#include <errno.h>
#define NAMED_PIPE "/var/lock/pipename"
// shared data struct
struct message
{
int pid;
int counter;
};
int main(int argc, char **argv)
{
// create the named pipe (fifo) with permission
int ret = mkfifo(NAMED_PIPE, 0666);
if (ret < 0)
printf("Error when creating FIFO. %s\n", strerror(errno));
// create a child process by calling folk,
// it returns a non-zero pid for parent process and 0 for child process created
pid_t pid = fork();
//--- the parent process will write to the pipe only
if (pid != 0)
{
int fd = open(NAMED_PIPE, O_WRONLY);
for (int i = 0; i < 5; i++)
{
message msg;
msg.pid = pid;
msg.counter = i;
printf("Process %d: Write %d.\n", pid, i);
ret = write(fd, &msg, sizeof(msg));
if (ret < 0)
printf("Process %d: Error while writing message. %s\n", pid, strerror(errno));
sleep(0.1);
}
close(fd);
}
//-- child process will read only
else
{
int fd = open(NAMED_PIPE, O_RDONLY);
for (int i = 0; i < 5; i++)
{
message msg;
ret = read(fd, &msg, sizeof(msg));
if (ret < 0)
printf("Process %d: Error while reading message. %s\n", pid, strerror(errno));
printf("Process %d: Received value %d from the parent process %d.\n", pid, msg.counter, msg.pid);
sleep(0.1);
}
close(fd);
}
unlink(NAMED_PIPE);
return 0;
}
์์ ๋ฅผ ๋น๋ํ๊ณ ์คํํฉ๋๋ค.
gcc named_pipe.cpp -I/usr/local/include/ -L/usr/local/lib -o named_pipe
./named_pipe
ํ๋ก๊ทธ๋จ์ ์ถ๋ ฅ:
Process 17830: Write 0.
Process 17830: Write 1.
Process 17830: Write 2.
Process 0: Received value 0 from the parent process 17830.
Process 17830: Write 3.
Process 0: Received value 1 from the parent process 17830.
Process 17830: Write 4.
Process 0: Received value 2 from the parent process 17830.
Process 0: Received value 3 from the parent process 17830.
Process 0: Received value 4 from the parent process 17830.
2.3 UNIX Domain Socket
UNIX Domain Socket์ ์ ์ฉํ ๋ด์ฅ ๊ธฐ๋ฅ์ด ๋ง์ ํ๋ก์ธ์ค ๊ฐ์ ํต์ ์ฑ๋์ ์ค์ ํ ์ ์์ด ํธ๋ฆฌํฉ๋๋ค. TCP/IP ์ธํฐ๋ท ์์ผ์ผ๋ก stream-oriented(TCP) ๋ฐ datagram-oriented(UDP) ํ๋กํ ์ฝ์ ๋ชจ๋ ์ง์ํฉ๋๋ค. blocking์ non-blocking์ค์์ ์ ํํ ์๋ ์์ต๋๋ค.
๋จผ์ 'socket'ํจ์๋ก ์์ผ์ ๋ง๋ค ๋ ๋๋ฉ์ธ ์์ผ์ผ๋ก ์ง์ (AF_UNIX)ํด์ผ ํฉ๋๋ค. ์์ฑ๋ ํ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์์ผ์ ๊ณ ์ ํ ํ์ผ ๊ฒฝ๋ก์ ๋ฐ์ธ๋ฉ(bind)ํด์ผ ํฉ๋๋ค. ์์ผ์ด ๊ณ ์ ํ IP ์ฃผ์ ๋ฐ ํฌํธ ๋ฒํธ์ ๋ฐ์ธ๋ฉ๋๋ ์ธํฐ๋ท ์์ผ(AF_INET)๊ณผ ๋ฌ๋ฆฌ UNIX Domain Socket์ ํ์ผ ๊ฒฝ๋ก์ ๋ฐ์ธ๋ฉ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ฉด ํ์ผ ์์คํ ์ ํ์ผ์ด ์์ฑ๋๊ณ , ํ๋ก๊ทธ๋จ์ด ๋ซํ ํ ํ์ผ์ด ๋ ์ด์ ํ์ํ์ง ์์ผ๋ฉด ์๋์ผ๋ก ์ ๊ฑฐํด์ผ ํฉ๋๋ค.
์๋ ์์ ์์๋ ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์ ์ฐ๊ฒฐํ์ฌ 'hello'ํ๊ณ ์๋ฒ๋ก๋ถํฐ ์๋ต์ ๋ฐ์ต๋๋ค.
/**
* Sample for UNIX domain socket
* Two-way communication between process server and client:
* 1) Client connect and say hello to server
* 2) Server receive client message and display
* 3) Server say hello back to client
* 4) Client receive server message and display
* 5) Done.
*/
#include <unistd.h> // for fork()
#include <stdio.h> // for printf
#include <stdlib.h> // for exit()
#include <sys/socket.h>
#include <sys/un.h> // socket in Unix
// for print error message
#include <string.h>
#include <errno.h>
#define SERVER_SOCK_PATH "unix_sock.server"
#define CLIENT_SOCK_PATH "unix_sock.client"
#define SERVER_MSG "HELLO FROM SERVER"
#define CLIENT_MSG "HELLO FROM CLIENT"
int main(int argc, char **argv)
{
struct sockaddr_un server_addr;
struct sockaddr_un client_addr;
memset(&server_addr, 0, sizeof(server_addr));
memset(&client_addr, 0, sizeof(client_addr));
int rc;
// for simplicity, we will assign a fixed size for buffer of the message
char buf[256];
// create two processes of client and server
pid_t pid = fork();
//---------- SERVER PROCESS
if (pid != 0)
{
// maximum number of client connections in queue
int backlog = 10;
/****************************************************/
/* Open the server socket with the SOCK_STREAM type */
/****************************************************/
int server_sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (server_sock == -1)
{
printf("SERVER: Error when opening server socket.\n");
exit(1);
}
/*************************************/
/* Bind to an address on file system */
/*************************************/
// similar to other IPC methods, domain socket needs to bind to a file system
// so that client know the address of the server to connect to
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, SERVER_SOCK_PATH);
int len = sizeof(server_addr);
// unlink the file before bind, unless it can't bind
unlink(SERVER_SOCK_PATH);
rc = bind(server_sock, (struct sockaddr *)&server_addr, len);
if (rc == -1)
{
printf("SERVER: Server bind error: %s\n", strerror(errno));
close(server_sock);
exit(1);
}
/***************************************/
/* Listen and accept client connection */
/***************************************/
// set the server in the "listen" mode and maximum pending connected clients in queue
rc = listen(server_sock, backlog);
if (rc == -1)
{
printf("SERVER: Listen error: %s\n", strerror(errno));
close(server_sock);
exit(1);
}
printf("SERVER: Socket listening...\n");
int client_fd = accept(server_sock, (struct sockaddr *) &client_addr, (socklen_t*)&len);
if (client_fd == -1)
{
printf("SERVER: Accept error: %s\n", strerror(errno));
close(server_sock);
close(client_fd);
exit(1);
}
printf("SERVER: Connected to client at: %s\n", client_addr.sun_path);
printf("SERVER: Wating for message...\n");
/********************/
/* Listen to client */
/********************/
memset(buf, 0, 256);
int byte_recv = recv(client_fd, buf, sizeof(buf), 0);
if (byte_recv == -1)
{
printf("SERVER: Error when receiving message: %s\n", strerror(errno));
close(server_sock);
close(client_fd);
exit(1);
}
else
printf("SERVER: Server received message: %s.\n", buf);
/**********************/
/* Response to client */
/**********************/
printf("SERVER: Respond to the client...\n");
memset(buf, 0, 256);
strcpy(buf, SERVER_MSG);
rc = send(client_fd, buf, strlen(buf), 0);
if (rc == -1)
{
printf("SERVER: Error when sending message to client.\n");
close(server_sock);
close(client_fd);
exit(1);
}
printf("SERVER: Done!\n");
close(server_sock);
close(client_fd);
remove(SERVER_SOCK_PATH);
}
//---------- CLIENT PROCESS
else
{
/**************************************************/
/* Open a client socket (same type as the server) */
/**************************************************/
int client_sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (client_sock == -1)
{
printf("CLIENT: Socket error: %s\n", strerror(errno));
exit(1);
}
/********************************************/
/* Bind client to an address on file system */
/********************************************/
// Note: this binding could be skip if we want only send data to server without receiving
client_addr.sun_family = AF_UNIX;
strcpy(client_addr.sun_path, CLIENT_SOCK_PATH);
int len = sizeof(client_addr);
unlink (CLIENT_SOCK_PATH);
rc = bind(client_sock, (struct sockaddr *)&client_addr, len);
if (rc == -1)
{
printf("CLIENT: Client binding error. %s\n", strerror(errno));
close(client_sock);
exit(1);
}
/****************************************/
/* Set server address and connect to it */
/****************************************/
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, SERVER_SOCK_PATH);
rc = connect(client_sock, (struct sockaddr*)&server_addr, len);
if(rc == -1)
{
printf("CLIENT: Connect error. %s\n", strerror(errno));
close(client_sock);
exit(1);
}
printf("CLIENT: Connected to server.\n");
/**************************/
/* Send message to server */
/**************************/
memset(buf, 0, sizeof(buf));
strcpy(buf, CLIENT_MSG);
rc = send(client_sock, buf, sizeof(buf), 0);
if (rc == -1)
{
printf("CLIENT: Send error. %s\n", strerror(errno));
close(client_sock);
exit(1);
}
printf("CLIENT: Sent a message to server.\n");
/**************************************/
/* Listen to the response from server */
/**************************************/
printf("CLIENT: Wait for respond from server...\n");
memset(buf, 0, sizeof(buf));
rc = recv(client_sock, buf, sizeof(buf), 0);
if (rc == -1)
{
printf("CLIENT: Recv Error. %s\n", strerror(errno));
close(client_sock);
exit(1);
}
else
printf("CLIENT: Message received: %s\n", buf);
printf("CLIENT: Done!\n");
close(client_sock);
remove(CLIENT_SOCK_PATH);
}
return 0;
}
์์ ๋ฅผ ๋น๋ํ๊ณ ์คํํฉ๋๋ค.
gcc unix_domain_socket.cpp -I/usr/local/include/ -L/usr/local/lib -o unix_domain_socket
./unix_domain_socket
ํ๋ก๊ทธ๋จ์ ์ถ๋ ฅ:
SERVER: Socket listening...
SERVER: Connected to client at: unix_sock.client
SERVER: Wating for message...
CLIENT: Connected to server.
CLIENT: Sent a message to server.
CLIENT: Wait for respond from server...
SERVER: Server received message: HELLO FROM CLIENT.
SERVER: Respond to the client...
SERVER: Done!
CLIENT: Message received: HELLO FROM SERVER
CLIENT: Done!
์ฐธ๊ณ
- Communication between processes in C/C++: https://biendltb.github.io/tech/inter-process-communication-ipc-in-cpp/
'Study: ComputerScience(CS) > CS: Network' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Network] HTTP ๋ฒ์ ๋ณ ํน์ง: HTTP v0.9 v1.0 v1.1 v2 v3 (0) | 2023.02.15 |
---|---|
[Network] Message Queue(๋ฉ์์ง ํ) ์ ๋ฆฌ: MQTT (0) | 2023.02.06 |
[Network] ํ๋ก์ธ์ค ๊ฐ ํต์ ๋ฐฉ๋ฒ: IPC(Inter Process Communication) (0) | 2023.01.08 |
[Network] Socket ์์ผ ํ๋ก๊ทธ๋๋ฐ (feat. sockaddr_in, IPv4...) (2) | 2022.12.16 |
[Network] Message Queue(๋ฉ์์งํ) ์ ๋ฆฌ (0) | 2022.11.26 |