Socket is defined by a 5-tuple
e.g., 2개의 브라우저가 example.com의 80번 포트에 동시접속 하는 경우
- Local IP address: 브라우저를 실행한 컴퓨터의 IP 주소
- Local port: 각 브라우저의 인스턴스의 로컬 포트번호
- Remote IP address: example.com의 IP주소
- Remote port: 80
- Protocol(TCP or UDP): TCP
→ 두 브라우저의 소켓에서 Local IP, Remote IP, Remote port, Protocol 값은 똑같음
UNIX 시스템 콜 - open, read, write, close
Open()
int open (const char* Path, int flags);
- Path: open 하려는 파일의 pathname
- flags:
- file access mode
- O_RDONLY: reading만 가능
- O_WRONLY: write만 가능
- O_RDWR: read, write만 가능
- any combination
- O_APPEND: 파일의 offset이 파일의 끝으로 이동하여 이어쓰기 가능
- O_CREAT: 없는 파일이면 새로 생성
- O_EXCL: 파일이 있는데 O_CREAT를 fail 발생시킴
- O_TRUNC: 파일 길이를 0으로 세팅
- 리턴값
- 성공: fd
- 실패: -1
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
extern int errno;
int main(){
// if file does not have in directory
// then file foo.txt is created.
int fd = open("foo.txt", O_RDONLY | O_CREAT);
printf("fd = %d\n", fd);
if (fd == -1) {
// print which type of error have in a code
printf("Error Number % d\n", errno);
// print program detail "Success or failure"
perror("Program");
}
return 0;
}
read()
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
- fd: read하려는 파일의 fd
- buf: read한 내용을 저장하는 곳
- count: 읽으려는 바이트 수
- 리턴값
- 성공: 읽은 바이트 수
- 실패: -1
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(){
int fd, sz;
char* c = (char*)calloc(100, sizeof(char));
fd = open("foo.txt", O_RDONLY);
if (fd < 0) {
perror("r1");
exit(1);
}
sz = read(fd, c, 10);
printf("called read(% d, c, 10). returned that"
" %d bytes were read.\n",
fd, sz);
c[sz] = '\0';
printf("Those bytes are as follows: % s\n", c);
return 0;
}
write()
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
- fd: write 연산을 수행할 파일의 fd
- buf: write할 내용이 있는 버퍼의 포인터
- count: write할 바이트 수
- 리턴값
- 성공: write한 바이트 수
- 실패: -1
#include<stdio.h>
#include <fcntl.h>
main(){
int sz;
int fd = open("foo.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0){
perror("r1");
exit(1);
}
sz = write(fd, "hello geeks\n", strlen("hello geeks\n"));
printf("called write(% d, \"hello geeks\\n\", %d)."
" It returned %d\n", fd, strlen("hello geeks\n"), sz);
close(fd);
}
close()
#include <unistd.h>
int close(int fd);
- fd: close할 파일의 fd
- 리턴값
- 성공: 0
- 실패: -1
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(){
int fd1 = open("foo.txt", O_RDONLY);
if (fd1 < 0) {
perror("c1");
exit(1);
}
printf("opened the fd = % d\n", fd1);
// Using close system Call
if (close(fd1) < 0) {
perror("c1");
exit(1);
}
printf("closed the fd.\n");
}
ifaddrs 구조체
getifaddrs()
int getifaddrs(struct ifaddrs **ifap);
void freeifaddrs(struct ifaddrs *ifa);
- 로컬 시스템에서 네트워크 인터페이스의 정보를 얻는 함수
- 네트워크 인터페이스의 정보를
struct ifaddrs
라는 구조체에 저장하고 구조체들을 링크드리스트 형태로 만듦 - *ifap: 구조체 링크드리스트의 첫 번째 ifaddrs 구조체를 가리킴
addrinfo 구조체
네트워크 소켓의 두 가지 유형: Connection-oriented, Connectionless
Connection-oriented
- TCP
- 데이터 도착 순서를 보장
- 데이터가 두 번 도착하여 중복되지 않도록 방지
- HTTP, SMTP, FTP, SSH
Connectionless
- UDP
- 각 패킷을 독립적으로 처리 → 프로토콜 관점에서, 중복 데이터도 별개의 데이터로 처리함
- 패킷이 도착할 거라는 보장X → 패킷이 도착하지 않았을 때 이를 알릴 방법도 없음
- 패킷이 순서대로 도착할 거라는 보장X
Socket functions
- socket(): 새로운 소켓 생성
- bind(): 소켓에 IP, port 주소 할당
- listen(): 서버 입장에서 사용, 새로운 연결 요청 기다림
- connect(): 클라이언트 입장에서 사용, TCP 연결 요청 전송
- accept(): 서버 입장에서 사용, 새로운 소켓의 TCP 연결 요청 수락
위 세 개 listen, connect, accept는 TCP 연결에만 존재
- send(), recv(): 데이터 교환
- sendto(), recvfrom(): 데이터 교환 시 대상 주소를 명시 (UDP)
- close(): 소켓 종료 (TCP의 경우, connection terminate)
- shutdown(): TCP에서 소켓의 특정 방향 통신을 중단
- select(): 여러 소켓을 모니터링
- getnameinfo(), getaddrinfo(): hostname, port 정보를 주소 정보로 변환
- setsockopt(): 소켓 옵션 설정
- fcntl(): 소켓 옵션 보기
TCP program flow
Client
- TCP 서버의 주소를 알아야 함 → client프로그램을 실행할 때 커맨드 라인에 서버의 hostname(IP), 포트번호를 같이 입력해서 알려줌
- 입력받은 주소(e.g., www.example.com)를 getaddrinfo()를 호출하여
struct addrinfo
구조체로 변환 - socket() 호출하여 소켓 생성
- connect() 호출하여 새로운 TCP connection을 설정
→ 성공적으로 연결되면 send()와 recv()를 사용하여 데이터 교환
Server
- 특정 포트와 인터페이스에서 연결 요청을 수신하도록 설정
→struct addrinfo
구조체를 사용하여 올바른 IP, port 주소로 초기화 - socket() 호출하여 소켓 생성
→ bind() 호출하여 생성된 소켓을 올바른 IP, port주소에 바인딩 - listend() 호출하여 소켓이 새로운 연결을 기다리는 상태로 만듦
- accept() 호출하여 새로운 연결 요청을 수락
→ 연결 성공: 새로운 소켓을 리턴
→ 리턴한 소켓으로 client와 recv(), send() 함수로 데이터 교환 - client가 여러 개인 경우, 처음 만든 소켓은 계속해서 새로운 연결 요청을 수락하는 상태로 유지
→ accept()를 반복적으로 호출 → 여러 client를 처리
UDP program flow
Client
UDP client 프로그램은 TCP와 달리 연결을 설정하지 않고 데이터를 주고 받기 때문에 remote UDP peer의 주소를 알고 첫 번째 패킷을 전송해야 한다.
- getaddrinfo()를 호출하여 주소를
struct addrinfo
로 변환 - sendto() 호출하여 첫 번째 패킷을 전송
- sendto(), recvfrom()을 반복 호출하여 추가적인 패킷을 송수신
- TCP와 달리 handshake 과정이 없기 때문에 데이터를 먼저 보내야만 데이터를 받을 수 있음
Server
struct addrinfo
를 사용하여 올바른 IP, port 주소로 초기화
→ getaddrinfo()를 호출하여 프로토콜에 독립적인 주소 정보를 설정
→ UDP client로부터의 연결을 수신- socket() 호출하여 새로운 소켓 생성
→ bind() 호출하여 생성된 소켓을 올바른 IP, port 주소에 바인딩 - recvfrom() 호출하여 client로부터 데이터 수신
→ recvfrom()은 데이터 수신할 때까지 block 상태임 - sendto()로 첫 번째로 수신한 데이터에 대한 응답을 전송
4-1. 추가 데이터 수신을 위해 recvfrom()을 반복 호출할 수 있음
'CS > Network' 카테고리의 다른 글
04_Multiprocess (2) | 2024.07.24 |
---|---|
03_TCP Connections (0) | 2024.07.24 |
TCP flow control이란? (0) | 2024.03.18 |
다중화와 역다중화 (0) | 2024.02.01 |
OSI 7계층 모델과 TCP/IP 4계층 모델 비교 (0) | 2024.01.31 |