헤더 : <sys/socket.h>
<서버>
socket() : 소켓 생성 함수
int socket(int domain, int type, int protocol);
-첫번째 매개변수 : 어떤 영역에서 통신할 건지 영역 지정 ( protocol family )
- AF_INET : ipv4 / AF_INET6 : ipv6
-두번째 매개변수 : 어떤 서비스 타입의 소켓을 생성할건지 지정( socket type )
- SOCK_STREAM : TCP
- SOCK_DGRAM : UDP
- SOCK_RAW : TCP,UDP를 거치지 않고 바로 IP 계층 사용
-세번째 매개변수 : 소켓에서 사용할 프로토콜 지정
- IPPROTO_TCP : TCP / IPPROTO_UDP : UDP
- 0 : socket type에서 이미 정해진 경우
성공 => 소켓 디스크립터(0 이상)
실패 => -1
bind() : 서버의 ip주소와 port를 소켓에 할당해주는 함수
- client가 server의 소켓 디스크립터번호를 알아야 하기 때문에 사용
int bind(int sockfd, struct sockaddr* myaddr, socklen_t addrlen);
-첫번째 매개변수 : ip,port를 할당해줄 서버 소켓 디스크립터 번호
-두번째 매개변수 : 서버의 ip를 담고있는 sockaddr 구조체의 주소값
-세번째 매개변수 : 서버정보가 담긴 serv_addr 구조체 길이
성공 => 0
실패 => -1
listen() : client에서 요청이 오면 수락할 수 있도록 대기상태에 들어가는 함수
int listen(int sockfd, int backlog);
-첫번째 매개변수 : 서버 소켓 디스크립터
-두번째 매개변수 : client가 대기할 수 있는 대기열의 크기를 지정
성공 => 0
실패 => -1
accept() : 서버에 client를 연결하는 함수
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
- 첫번째 매개변수 : 서버 소켓 디스크립터
- 두번째 매개변수 : 연결된 클라이언트의 ip주소 정보를 담을 sockaddr 구조체 주소
- 세번째 매개변수 : 연결된 클라이언트 정보가 담길 sockaddr 구조체 길이
<클라이언트>
connect() : 서버로 연결요청하는 함수
int connect(int sockfd, struct sockaddr* serv_addr, socklen_t addrlen);
- 첫번째 매개변수 : 서버와 통신하기 위한 소켓 디스크립터
- 두번째 매개변수 : 연결할 서버의 ip,port정보를 담고 있는 sockaddr 구조체 주소
- 세번째 매개변수 : 연결할 서버의 정보가 담긴 sockaddr 구조체 길이
성공 => 0
실패 => -1
close() : 소켓을 닫고 통신을 종료하는 함수
-<unistd.h>
int close(int sockfd);
성공 => 0
실패 => -1
server 구현 => client, server소켓 둘 다 생성
client 구현 => 소켓 1개만 생성
( 서버의 정보를 담고있는 sockaddr 구조체를 이 소켓에 담음).
( connect()로 서버와 연결해서 그 때 담는다. )
<소켓 통신에서 주의사항>
- 소켓을 보낼 때 내가 fgets로 100까지 읽어오라고 해도, 정확히 100까지 읽는다는 보장 X.
- tcp는 그나마 신뢰성 통신이라 드물긴 하지만, udp인 경우에는 더 드라마틱하게 이상하게 보내질 때가 많음.
그렇기 때문에 fgets(req_line,100,clnt_read) 같은 형태로 소켓으로부터 데이터를 읽어오도록 해도 100만큼 정확히 읽어 온단 보장이 없기 때문에 조건을 걸어서
(EX : \r\n을 만나기 전까진 버퍼에서 보내지 말고 버퍼 뒤에 이어붙여라)
완전히 원하는 만큼 데이터가 보내지도록 개발자가 보장을 직접 해줘야 함.
<소켓 통신시 발생하는 문제점>
문제점
- 전송측은 빅 엔디안으로 전송 / 받는 쪽은 리틀 엔디안으로 처리
=>서버와 클라이언트의 바이트 정렬 방식이 다르기 때문
해결방법
- 받는 측(리틀 엔디안)에서 전송받은 데이터(빅 엔디안)를 뒤집어서 처리!!
=> 개발자가 해야 할 것 : port번호, ip주소만 직접 처리해주면 됨.
=> 기본적으로 pc는 리틀 엔디안이므로 이를 빅 엔디안으로 변경해야함.
포트 : 2byte로 이루어짐
IP : 4byte로 이루어짐