(리눅스 시스템 프로그래밍) OS Socket Programming + C예제코드
by 줌코딩
Socket Programming이란?
- 두개의 노드를 네트워크 상에서 커뮤니케이션하는 방법 중 하나이다.
- 하나의 socket이 IP의 특정 port에서 listen하고
- 다른 하나의 socket이 connection을 만들어서 접근한다.
- 주로 Server가 listener socket의 역할을 하고 client가 접근하는 socket이 된다.
Stages for Server
int socket_created = socket(domain, type, protocol);
- domain : communication domain을 의미(주소 체계 나타내는 프로토콜)
- 예를 들어, AF_INET(IPv4 protocol), AF_INET6(IPv6 protocol)이 있다.
- type : communication type을 의미한다.
- 예를 들어, SOCK_STREAM(TCP), SOCK_DGRAM(UDP)
- 여기서 TCP와 UDP의 차이는 데이터를 보내고 확인이 가능한가 안한가의 차이이다. UDP는 걍 보냄
- protocol : protocl value for internet Protocol.
bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- 생성 후에 socket을 해당 IP의 Port로 엮어준다.
listen(int sockfd, int backlog);
- 서버 socket이 passive mode이면(bind 됐다면) client가 다가올 때까지 기다린다.
- backlog는 queue의 maximum length를 의미한다.
int new_socket= accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- listening socket에 들어온 connection request를 extract한다.
- responsive한 통신을 위해 listening socket을 계속 listening에만 집중할 수 있게 한다.
Stages for Client
- Socket을 생성하는 과정은 서버와 같다.
connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- client socketfd와 서버 IP Port address에다가 conenction을 생성하는 함수
예제 코드
server.c
// Partly taken from https://www.geeksforgeeks.org/socket-programming-cc/
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
void child_proc(int conn){
char buf[1024] ;
char * data = 0x0 ;
int len = 0 ;
int s ;
while ( (s = recv(conn, buf, 1023, 0)) > 0 ) {
buf[s] = 0x0 ;
if (data == 0x0) {
data = strdup(buf) ;
len = s ;
}
//다시 메모리할당해줘요
else {
data = realloc(data, len + s + 1) ;
strncpy(data + len, buf, s) ;
data[len + s] = 0x0 ;
len += s ;
}
}
printf(">%s\n", data) ;
//conn한테 다시 데이터를 보내줘요
//s 만큼만 보내줄거에요 반복해요
while (len > 0 && (s = send(conn, data, len, 0)) > 0) {
data += s ;
len -= s ;
}
shutdown(conn, SHUT_WR) ;
if (data != 0x0) free(data) ;
}
int main(int argc, char const *argv[])
{
int listen_fd, new_socket ;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};
listen_fd = socket(AF_INET /*IPv4*/, SOCK_STREAM /*TCP*/, 0 /*IP*/) ;
if (listen_fd == 0) {
perror("socket failed : ");
exit(EXIT_FAILURE);
}
memset(&address, '0', sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY /* the localhost*/ ;
address.sin_port = htons(8080);
if (bind(listen_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed : ");
exit(EXIT_FAILURE);
}
while (1) {
if (listen(listen_fd, 16 /* the size of waiting queue*/) < 0) {
perror("listen failed : ");
exit(EXIT_FAILURE);
}
//message가 들어오면 시작해봅시다
//new comer를 위해서 new socket을 생성해주자
new_socket = accept(listen_fd, (struct sockaddr *) &address, (socklen_t*)&addrlen) ;
if (new_socket < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
if (fork() > 0) {
//child보고 일하라고 하고 parent는 리스닝 다시
child_proc(new_socket) ;
}
else {
close(new_socket) ;
}
}
}
client.c
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
int main(int argc, char const *argv[]) {
struct sockaddr_in serv_addr;
int sock_fd ;
int s, len ;
char buffer[1024] = {0};
char * data ;
sock_fd = socket(AF_INET, SOCK_STREAM, 0) ;
if (sock_fd <= 0) {
perror("socket failed : ") ;
exit(EXIT_FAILURE) ;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
perror("inet_pton failed : ") ;
exit(EXIT_FAILURE) ;
}
if (connect(sock_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("connect failed : ") ;
exit(EXIT_FAILURE) ;
}
scanf("%s", buffer) ;
data = buffer ;
len = strlen(buffer) ;
s = 0 ;
while (len > 0 && (s = send(sock_fd, data, len, 0)) > 0) {
data += s ;
len -= s ;
}
shutdown(sock_fd, SHUT_WR) ;
char buf[1024] ;
data = 0x0 ;
len = 0 ;
while ( (s = recv(sock_fd, buf, 1023, 0)) > 0 ) {
buf[s] = 0x0 ;
if (data == 0x0) {
data = strdup(buf) ;
len = s ;
}
else {
data = realloc(data, len + s + 1) ;
strncpy(data + len, buf, s) ;
data[len + s] = 0x0 ;
len += s ;
}
}
printf(">%s\n", data);
}
느낀점
- socket programming의 목적을 알겠다.
- 그리고 socket을 통해서 client와 server가 통신할 수 있게 한 것은 매우 혁신적인 것 같다.
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
Subscribe via RSS