티스토리 뷰

socket으로 기본적인 서버 프로그램을 만들어보자.

프로그램은 하나의 클라이언트를 처리하며, 받은 데이터를 다시 클라이언트에게 전달하는 echo기능을 수행한다.




#include <socket.h>

#include <stat.h>

#include <inet.h>

#include <stdio.h>

#include <string.h>

#include <unistd.h>

 

#define BUF_SIZE 1024

 

int main(){

int server_socket, client_socket;

int client_len, n;

char buf[BUF_SIZE];

struct sockaddr_in client_addr, server_addr;

client_len = sizeof(client_addr);


// 소켓을 생성한다.

if((server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) == -1){

printf("socket error\n");

return 0;

}


// 서버의 ip주소와 port번호를 sockaddr_in 구조체에 저장한다.

memset(&server_addr, 0, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

server_addr.sin_port = htons(3500);


// 구조체에 저장한 주소를 socket에 연결한다.

bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));


// 클라이언트의 연결을 기다린다.

listen(server_socket, 5);


// 반복

while(1){

memset(buf, 0, BUF_SIZE);


// 클라이언트의 연결을 수락한다.

client_socket = accept(server_socket, (struct sockaddr*)&client_addr, sizeof(client_len));


printf("new client : %s\n", inet_ntoa(client_addr.sin_addr));


// 클라이언트로부터 전달받은 데이터를 읽는다.

if((n = read(client_socket, buf, BUF_SIZE) <= 0){

close(client_socket);

continue;

}


// 전달받은 데이터를 다시 전송한다.

if(write(client_socket, buf, BUF_SIZE) <= 0){

printf("write error\n");

close(client_socket);

}


// 클라이언트 소켓을 종료한다.

close(client_socket);

}


// 서버 소켓을 종료한다.

close(server_socket);

return 0;

}




서버 프로그램의 흐름인 socket() - bind() - listen() - accept() - read()/write() - close() 함수를 중점적으로 코드를 다시 보자.




server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)


IPv4를 사용하며(AF_INET), TCP/IP 프로토콜을 사용하는(SOCK_STREAM/IPPROTO_TCP) socket을 생성했다. 생성된 socket은 아직 주소와 포트와 연결되지 않았다.




memset(&server_addr, 0, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

server_addr.sin_port = htons(3500);


bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));


먼저 서버의 ip주소와 port번호를 sockaddr_in구조체에 채운다. sockaddr_in구조체는 ip주소와 port번호를 맴버로 가지고 있는 구조체이다.

* 네트워크 통신을 할 때 주의해야 할 점은 네트워크 바이트 순서와 일반 컴퓨터의 바이트 순서가 다르다는 것인데 hton*() ntoh*() 함수로 네크워크 바이트로 데이터를 변환해서 통신해야 한다. 자세한 내용은 (글 링크)




listen(server_socket, 5);


server_socket으로 들어오는 클라이언트의 요청을 최대 5개 까지 기다린다. 보통 5 값을 사용한다.




client_socket = accept(server_socket, (struct sockaddr*)&client_addr, sizeof(client_len));


server_socket으로 연결 요청이 온 클라이언트 소켓을 받아들인다. 클라이언트 소켓의 소켓번호가 반환되고, client_addr 구조체에 클라이언트의 ip주소, port번호가 저장된다.




= read(client_socket, buf, BUF_SIZE)


클라이언트 소켓으로부터 데이터를 읽어온다. 반환되는 값은 읽은 데이터의 길이로 0이하의 값이 반환되면 데이터를 읽지 않았다는 뜻으로 이 프로그램에서는 소켓을 종료한다.




write(client_socket, buf, BUF_SIZE)


클라이언트 소켓에 buf데이터를 쓴다. 반환되는 값은 실제로 쓴 데이터의 크기이다. 0이하의 값이 반환되면 쓰기에 문제가 생겼다는 뜻으로 소켓을 종료한다.




close(client_socket);

close(server_socket);


소켓을 종료한다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함