소켓 정리
Language/C 2011. 11. 2. 18:451. Byte Order
네트워크 상에서의 데이터 저장 방식은(Network Byte Order)는 Big Endian 이다.
네트워크 관련 데이터를 채우거나 패킷을 생성할 때 Network Byte Order로 형성을 해 주어야 될 때가 있는데,
이때에는 다음과 같은 함수를 이용해 Host Byte Order의 수를 Network Byte Order로 바꾸어 줄 수가 있다.
만약 이미 Network Byte Order의 수를 htonl 을 써서 Network Byte Order을 만들고자 한다면?
함수는 실행되지 않는다.
2. 구조체
2-1. addrinfo
이 구조체는 소켓을 만들 때 필요한 정보들을 얻기위한 구조체이다.
몇몇 요소들을 채운 뒤 getaddrinfio()함수를 실행하면 함수가 필요한 정보를 가진 linked list를 반환해준다
ai_flags : AI_PASSIVE를 넣을 시 localhost의 관련 정보들을 얻을 수 있다
ai_family : IPv4를 이용할시 AF_INET, IPv6을 이용할 시 AF_INET6, 정해져있지 않을 시 AF_UNSPEC을 넣는다
ai_socktype : 스트림 소켓이면 SOCK_STREAM, 데이터그램 소켓이면 SOCK_DGRAM을 넣는다
ai_protocol : 0을 넣을 시 모든 프로토콜 관련 정보를 얻을 수 있고, 특정 프로토콜을 지정해 줄 수도 있다
ai_addrlen : ip주소의 길이를 가지고있다
ai_addr : sockaddr 구조체 포인터로, ip, port number 정보를 가지고 있다.
ai_cononname : hostname을 가르키는 포인터이다.
ai_next : 다음 노드를 가리키고 있다
2-2. sockaddr
sockaddr구조체는 IPv4용인 sockaddr_in, IPv6용인 sockaddr_in6으로 캐스팅될 수 있고, 그 반대도 가능하다.
IPv4
IPv6
2-3. ip주소의 입력과 출력
inet_pton()를 이용하여 구조체에 IP주소를 넣을 수 있으며
inet_ntop()를 이용하여 구조체에 있는 IP주소를 문자열로 얻을 수 있다.
3. 함수
3-1. 연결 - 클라이언트, 서버 공통
3-1-1.getaddrinfo()
addrinfo를 채워주는 함수이다
*hints에 몇몇 요소들을 기입한 addrinfo 구조체를 넣어주면
**res를 통해 linked list가 반환된다
함수 성공시 0이 반환된다.
예제1) 나의 localhost의 3490포트 정보 얻기
예제2)www.example.com의 3490포트 정보 얻기
3-1-2. socket()
소켓 파일 기술자를 생성한다
domain에는 PF_INET 또는 PF_INET6 이 들어가고, type에는 SOCK_STREAM 또는 SOCK_DGRAM, protocol에는 addrinfo 구조체의 protocol과 같다.
또 PF_INET과 PF_INET6은 각각 AF_INET과 AF_INET6으로 대신할 수 있다
함수 성공시 소켓 파일 기술자를 반환하고, 에러시 -1을 반환한다.
3-2. 연결 - 서버측
3-2-1. bind()
프로세스가 몇번 포트를 이용해 통신을 할 것인지 정해주는 함수이다
sockfd에는 소켓 파일 기술자, my_addr에는 bind할 곳의 주소 정보를 가지고 있는 sockaddr구조체, addrlen에는 주소의 길이를 넣어준다.
에러시 -1을 반환한다.
3-2-2. listen()
접속을 받아들일 준비를 하는 함수이다. backlog는 몇개의 연결까지 대기상태에 둘 것인지를 정해준다.
에러시 -1을 반환한다
3-2-3. accept()
대기중인 접속 하나를 받아드려 데이터를 주고받기 위한 함수이다.
성공시 새로운 소켓 파일 기술자를 반환하며, 이를 통해 데이터를 주고받을 수 있다
addr은 연결된 클라이언트의 주소가 들어갈 sockaddr_storage 구조체 포인터 변수를 넣어주고,
addrlen은 sockaddr_storage의 크기를 넣어준다
3-3. 연결 - 클라이언트측
3-3-1. connect()
서버에 접속을 하기위한 함수이다. serv_addr에는 접속할 곳의 주소가 들어가며, addrlen에는 주소의 길이를 넣어준다.
에러시 -1을 반환한다.
예제)www.example.com 의 3490포트에 접속
3-4. 데이터 송수신
3-4-1. 스트림 소켓 : send() recv()
accept()된 소켓 혹은 connect된 소켓을 이용해 데이터를 주고받기 위한 함수이다
send - msg에는 보낼 테이터, len에는 보낼 길이를 넣어준다
recv - buf에는 받을 데이터를 저장할 공간, len에는 받을 길이를 넣어준다
함수 종료시 실제 송,수신한 데이터의 길이를 반환하고, 에러시 -1을 반환한다
3-4-2. 데이터그램 소켓 : sendto() recvfrom()
send,recv함수와 비슷하지만 송신지or 수신지의 주소를 넣어주고, 구조체 변수의 크기를 넣어주어야 한다.
네트워크 상에서의 데이터 저장 방식은(Network Byte Order)는 Big Endian 이다.
네트워크 관련 데이터를 채우거나 패킷을 생성할 때 Network Byte Order로 형성을 해 주어야 될 때가 있는데,
이때에는 다음과 같은 함수를 이용해 Host Byte Order의 수를 Network Byte Order로 바꾸어 줄 수가 있다.
host to network short | |
host to network long | |
network to host short | |
network to host long |
만약 이미 Network Byte Order의 수를 htonl 을 써서 Network Byte Order을 만들고자 한다면?
함수는 실행되지 않는다.
2. 구조체
2-1. addrinfo
struct addrinfo { int ai_flags; // AI_PASSIVE, AI_CANONNAME, etc. int ai_family; // AF_INET, AF_INET6, AF_UNSPEC int ai_socktype; // SOCK_STREAM, SOCK_DGRAM int ai_protocol; // use 0 for "any" size_t ai_addrlen; // size of ai_addr in bytes struct sockaddr *ai_addr; // struct sockaddr_in or _in6 char *ai_canonname; // full canonical hostname struct addrinfo *ai_next; // linked list, next node };
이 구조체는 소켓을 만들 때 필요한 정보들을 얻기위한 구조체이다.
몇몇 요소들을 채운 뒤 getaddrinfio()함수를 실행하면 함수가 필요한 정보를 가진 linked list를 반환해준다
ai_flags : AI_PASSIVE를 넣을 시 localhost의 관련 정보들을 얻을 수 있다
ai_family : IPv4를 이용할시 AF_INET, IPv6을 이용할 시 AF_INET6, 정해져있지 않을 시 AF_UNSPEC을 넣는다
ai_socktype : 스트림 소켓이면 SOCK_STREAM, 데이터그램 소켓이면 SOCK_DGRAM을 넣는다
ai_protocol : 0을 넣을 시 모든 프로토콜 관련 정보를 얻을 수 있고, 특정 프로토콜을 지정해 줄 수도 있다
ai_addrlen : ip주소의 길이를 가지고있다
ai_addr : sockaddr 구조체 포인터로, ip, port number 정보를 가지고 있다.
ai_cononname : hostname을 가르키는 포인터이다.
ai_next : 다음 노드를 가리키고 있다
2-2. sockaddr
struct sockaddr { unsigned short sa_family; // address family, AF_xxx char sa_data[14]; // 14 bytes of protocol address };
sockaddr구조체는 IPv4용인 sockaddr_in, IPv6용인 sockaddr_in6으로 캐스팅될 수 있고, 그 반대도 가능하다.
IPv4
// (IPv4 only--see struct sockaddr_in6 for IPv6) struct sockaddr_in { short int sin_family; // Address family, AF_INET unsigned short int sin_port; // Port number struct in_addr sin_addr; // Internet address unsigned char sin_zero[8]; // Same size as struct sockaddr };
// (IPv4 only--see struct in6_addr for IPv6) // Internet address (a structure for historical reasons) struct in_addr { uint32_t s_addr; // that's a 32-bit int (4 bytes) };
IPv6
// (IPv6 only--see struct sockaddr_in and struct in_addr for IPv4) struct sockaddr_in6 { u_int16_t sin6_family; // address family, AF_INET6 u_int16_t sin6_port; // port number, Network Byte Order u_int32_t sin6_flowinfo; // IPv6 flow information struct in6_addr sin6_addr; // IPv6 address u_int32_t sin6_scope_id; // Scope ID }; struct in6_addr { unsigned char s6_addr[16]; // IPv6 address };
2-3. ip주소의 입력과 출력
inet_pton()를 이용하여 구조체에 IP주소를 넣을 수 있으며
inet_ntop()를 이용하여 구조체에 있는 IP주소를 문자열로 얻을 수 있다.
struct sockaddr_in sa; // IPv4 struct sockaddr_in6 sa6; // IPv6 inet_pton(AF_INET, "192.0.2.1", &(sa.sin_addr)); // IPv4 inet_pton(AF_INET6, "2001:db8:63b3:1::3490", &(sa6.sin6_addr)); // IPv6
// IPv4: char ip4[INET_ADDRSTRLEN]; // space to hold the IPv4 string struct sockaddr_in sa; // pretend this is loaded with something inet_ntop(AF_INET, &(sa.sin_addr), ip4, INET_ADDRSTRLEN); printf("The IPv4 address is: %s\n", ip4); // IPv6: char ip6[INET6_ADDRSTRLEN]; // space to hold the IPv6 string struct sockaddr_in6 sa6; // pretend this is loaded with something inet_ntop(AF_INET6, &(sa6.sin6_addr), ip6, INET6_ADDRSTRLEN); printf("The address is: %s\n", ip6);
3. 함수
3-1. 연결 - 클라이언트, 서버 공통
3-1-1.getaddrinfo()
#include <sys/types.h> #include <sys/socket.h> #include <netdb.h> int getaddrinfo(const char *node, // e.g. "www.example.com" or IP const char *service, // e.g. "http" or port number const struct addrinfo *hints, struct addrinfo **res);
addrinfo를 채워주는 함수이다
*hints에 몇몇 요소들을 기입한 addrinfo 구조체를 넣어주면
**res를 통해 linked list가 반환된다
함수 성공시 0이 반환된다.
예제1) 나의 localhost의 3490포트 정보 얻기
int status; struct addrinfo hints; struct addrinfo *servinfo; // will point to the results memset(&hints, 0, sizeof hints); // make sure the struct is empty hints.ai_family = AF_UNSPEC; // don't care IPv4 or IPv6 hints.ai_socktype = SOCK_STREAM; // TCP stream sockets hints.ai_flags = AI_PASSIVE; // fill in my IP for me if ((status = getaddrinfo(NULL, "3490", &hints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status)); exit(1); } // servinfo now points to a linked list of 1 or more struct addrinfos // ... do everything until you don't need servinfo anymore .... freeaddrinfo(servinfo); // free the linked-list
예제2)www.example.com의 3490포트 정보 얻기
int status; struct addrinfo hints; struct addrinfo *servinfo; // will point to the results memset(&hints, 0, sizeof hints); // make sure the struct is empty hints.ai_family = AF_UNSPEC; // don't care IPv4 or IPv6 hints.ai_socktype = SOCK_STREAM; // TCP stream sockets // get ready to connect status = getaddrinfo("www.example.net", "3490", &hints, &servinfo); // servinfo now points to a linked list of 1 or more struct addrinfos // etc.
3-1-2. socket()
#include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol);
소켓 파일 기술자를 생성한다
domain에는 PF_INET 또는 PF_INET6 이 들어가고, type에는 SOCK_STREAM 또는 SOCK_DGRAM, protocol에는 addrinfo 구조체의 protocol과 같다.
또 PF_INET과 PF_INET6은 각각 AF_INET과 AF_INET6으로 대신할 수 있다
함수 성공시 소켓 파일 기술자를 반환하고, 에러시 -1을 반환한다.
int s; struct addrinfo hints, *res; // do the lookup // [pretend we already filled out the "hints" struct] getaddrinfo("www.example.com", "http", &hints, &res); // [again, you should do error-checking on getaddrinfo(), and walk // the "res" linked list looking for valid entries instead of just // assuming the first one is good (like many of these examples do.) // See the section on client/server for real examples.] s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
3-2. 연결 - 서버측
3-2-1. bind()
#include <sys/types.h> #include <sys/socket.h> int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
프로세스가 몇번 포트를 이용해 통신을 할 것인지 정해주는 함수이다
sockfd에는 소켓 파일 기술자, my_addr에는 bind할 곳의 주소 정보를 가지고 있는 sockaddr구조체, addrlen에는 주소의 길이를 넣어준다.
에러시 -1을 반환한다.
struct addrinfo hints, *res; int sockfd; // first, load up address structs with getaddrinfo(): memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; // fill in my IP for me getaddrinfo(NULL, "3490", &hints, &res); // make a socket: sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); // bind it to the port we passed in to getaddrinfo(): bind(sockfd, res->ai_addr, res->ai_addrlen)
3-2-2. listen()
int listen(int sockfd, int backlog);
접속을 받아들일 준비를 하는 함수이다. backlog는 몇개의 연결까지 대기상태에 둘 것인지를 정해준다.
에러시 -1을 반환한다
3-2-3. accept()
#include <sys/types.h> #include <sys/socket.h> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
대기중인 접속 하나를 받아드려 데이터를 주고받기 위한 함수이다.
성공시 새로운 소켓 파일 기술자를 반환하며, 이를 통해 데이터를 주고받을 수 있다
addr은 연결된 클라이언트의 주소가 들어갈 sockaddr_storage 구조체 포인터 변수를 넣어주고,
addrlen은 sockaddr_storage의 크기를 넣어준다
#include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #define MYPORT "3490" // the port users will be connecting to #define BACKLOG 10 // how many pending connections queue will hold int main(void) { struct sockaddr_storage their_addr; socklen_t addr_size; struct addrinfo hints, *res; int sockfd, new_fd; // !! don't forget your error checking for these calls !! // first, load up address structs with getaddrinfo(): memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; // fill in my IP for me getaddrinfo(NULL, MYPORT, &hints, &res); // make a socket, bind it, and listen on it: sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); bind(sockfd, res->ai_addr, res->ai_addrlen); listen(sockfd, BACKLOG); // now accept an incoming connection: addr_size = sizeof their_addr; new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size); // ready to communicate on socket descriptor new_fd! . .
3-3. 연결 - 클라이언트측
3-3-1. connect()
#include <sys/types.h> #include <sys/socket.h> int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
서버에 접속을 하기위한 함수이다. serv_addr에는 접속할 곳의 주소가 들어가며, addrlen에는 주소의 길이를 넣어준다.
에러시 -1을 반환한다.
예제)www.example.com 의 3490포트에 접속
struct addrinfo hints, *res; int sockfd; // first, load up address structs with getaddrinfo(): memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; getaddrinfo("www.example.com", "3490", &hints, &res); // make a socket: sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); // connect! connect(sockfd, res->ai_addr, res->ai_addrlen);
3-4. 데이터 송수신
3-4-1. 스트림 소켓 : send() recv()
int send(int sockfd, const void *msg, int len, int flags);
int recv(int sockfd, void *buf, int len, int flags);
accept()된 소켓 혹은 connect된 소켓을 이용해 데이터를 주고받기 위한 함수이다
send - msg에는 보낼 테이터, len에는 보낼 길이를 넣어준다
recv - buf에는 받을 데이터를 저장할 공간, len에는 받을 길이를 넣어준다
함수 종료시 실제 송,수신한 데이터의 길이를 반환하고, 에러시 -1을 반환한다
3-4-2. 데이터그램 소켓 : sendto() recvfrom()
int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, socklen_t tolen);
int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);
send,recv함수와 비슷하지만 송신지or 수신지의 주소를 넣어주고, 구조체 변수의 크기를 넣어주어야 한다.
'Language > C' 카테고리의 다른 글
현재 날짜와 시간 출력 (0) | 2011.11.04 |
---|---|
gettimeofday (0) | 2011.11.04 |
getopt()와 optarg, optopt (0) | 2011.11.02 |
시리얼 통신 - 자료 수신을 위한 poll (0) | 2011.09.16 |
IPC - 파이프(PIPE)의 개념 (0) | 2011.09.16 |