TCP/IP Socket Programming 1

다나·2022년 12월 21일
0

컴퓨터 네트워크

목록 보기
4/6
post-thumbnail

리눅스 기반의 소켓 프로그래밍이니, 리눅스 내용이 일부 들어가있습니다!🍎
나중에 컴퓨터 네트워크 이후에 업로드될 리눅스 프로그래밍 관련 부분과 함께 참고하면 더 많은 내용을 알 수 있습니다✨

1. 네트워크 프로그래밍 🖥️

네트워크 프로그래밍은 소켓 프로그래밍이며, 네트워크로 연결된 둘 이상의 컴퓨터 사이에서의 데이터 송수신 프로그램의 작성이다.

2. 소켓 🧵

소켓은 네트워크의 연결 도구로 운영체제에 의해 제공되는 소프트웨어적인 장치이다.

3. 연결요청을 허용하는 소켓(서버 소켓)의 생성 과정 👩‍⚕️

  • 서버는 클라이언트보다 먼저 실행되어야 한다!

1) 소켓의 생성 : socket 함수 호출

#include <sys/socket.h>
int socket(int domain, int type, int protocol);
//성공시 파일 디스크립터, 실패시 -1을 반환한다.

2) IP와 Port 번호 할당(소켓의 주소 할당) : bind 함수 호출

#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen);
//성공시 0, 실패시 -1을 반환한다.

3) 연결요청 수락 가능 상태(서버 소켓)으로 변경 : listen 함수 호출

  • 서버 소켓은 SYN을 받으면, SYN+ACK을 전송한다.
#include <sys/socket.h>
int listen(int sockfd, int backlog);
//성공시 0, 실패시 -1을 반환한다.

4) 연결 요청에 대한 수락 : accept 함수 호출

  • 연결요청 수락시 데이터 송수신 가능하며, 데이터 송수신은 양방향으로 가능하다.
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//성공시 파일 디스크립터, 실패시 -1을 반환한다.

5) 데이터 송수신 : read, write 함수 호출
6) 연결 종료 : close 함수 호출

  • read, write, close는 리눅스 기반 파일 조작하기 부분을 참고!!

4. 연결 요청하는 소켓(클라이언트 소켓)의 구현 🕵️

1) 소켓의 생성 : socket 함수 호출

  • 서버 소켓 생성 과정에서 첫번째 과정인 소켓 생성(socket 함수 호출)과 동일하다.
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
//성공시 파일 디스크립터, 실패시 -1을 반환한다.

2) 연결 요청 : connect 함수 호출

#include <sys/socket.h>
int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen);
//성공시 0, 실패시 -1을 반환한다.

3) 데이터 송수신 : read, write 함수 호출
4) 연결 종료 : close 함수 호출

  • read, write, close는 리눅스 기반 파일 조작하기 부분을 참고!!

5. 리눅스 기반 파일 조작하기 🗂️

5-1. 저수준 파일 입출력

  • 운영체제가 제공하는 함수 기반의 파일 입출력. (ANSI 표준 함수가 아니다.)
  • 운영체제에 대한 호환성이 없다. (표준이 아니기 때문에)
  • 리눅스에서 소켓파일이다.
  • 따라서, 저수준 파일 입출력 함수를 기반으로 소켓 기반의 데이터 송수신이 가능하다.

5-2. 파일 디스크립터

  • 운영체제가 만든 파일(소켓)을 구분하기 위한 숫자이다.
  • 저수준 파일 입출력 함수는 입출력을 목적으로 파일 디스크립터를 요구한다.
  • 저수준 파일 입출력 함수에게 소켓의 파일 디스크립터를 전달한다.
    (소켓을 대상으로 입출력을 진행한다.)

5-3. 파일 열기와 닫기 (open, close)

1) open 함수

  • open 함수 호출시에 반환된 파일 디스크립터를 이용하여 파일 입출력을 진행한다.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *path, int flag);
//성공시 파일 디스크립터, 실패시 -1을 반환한다.

2) close 함수

#include <unistd.h>

int close(int fd);
//성공시 0, 실패시 -1을 반환한다.

5-4. 파일에 데이터 작성하기

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t nbytes);
//성공시 전달한 바이트 수, 실패시 -1을 반환한다.

예시) "Let's go!"를 "data.txt"파일에 작성한다.

int main(void){
	int fd;
    char buf[] = "Let's go!\n";
    fd = open("data.txt", O_CREAT|O_WRONLY|O_TRUNC);
    
    if(fd==-1)
    	error_handling("open() error!");	
        //error_handling 함수는 따로 정의해야하며, 해당 함수로 이동하면 현재 프로세스는 종료된다.
    printf("file descriptor : %d \n", fd);
    
    if(write(fd, buf, sizeof(buf)) == -1)
    	error_handling("write() error!");
    
    close(fd);
    return 0;
}

5-5. 파일에 저장된 데이터 읽기

#include <unistd.h>
ssize_t read(int fd, void* buf, size_t nbytes);
//성공시 수신한 바이트의 수(단, 파일의 끝을 만나면 0), 실패시 -1을 반환한다.

예시) "data.txt"파일의 내용을 buf에 읽어온다.

int main(void){
	int fd;
    char buf[BUF_SIZE];	//BUF_SIZE는 별도로 명시해줘야 한다.
    fd = open("data.txt", O_RDONLY);
    
    if(fd==-1)
    	error_handling("open() error!");	
        
    printf("file descriptor : %d \n", fd);
    
    if(read(fd, buf, sizeof(buf)) == -1)
    	error_handling("read() error!");
    
    close(fd);
    return 0;
}

5-6. 파일 디스크립터와 소켓 예시

  • socket 함수 호출 관련한 더 자세한 설명과 예시은 다음 글 참고 바람!
  • 일반 파일은 open 함수 호출로 파일 디스크립터를 생성하지만, 소켓 파일은 socket 함수 호출로 파일 디스크립터를 생성한다.
int main(void){
	int fd1, fd2, fd3;
    fd1 = socket(PF_INET, SOCK_STREAM, 0);	//소켓 생성
    fd2 = open("test.dat", O_CREAT|O_WRONLY|O_TRUNC);
    fd3 = socket(PF_INET, SOCK_DGRAM, 0); //소켓 생성
    
    printf("file descriptor : %d \n", fd1);
    printf("file descriptor : %d \n", fd2);
    printf("file descriptor : %d \n", fd3);

    close(fd1); close(fd2); close(fd3);
    return 0;
}
profile
컴퓨터공학과 학생이며, 백엔드 개발자입니다🐰

0개의 댓글