TCP/IP 기본 함수
int TCPIPconnect(const char *addr, int port)함수
TCP/IP에서 서버로 접속할 client의 connect함수입니다. 이 함수는 client가 server로 접속할 때에 IP address(예, 110.45.229.135) 이든지, domain(downman.tistory.com) 방식이든 아무 주소 형태로 접속할 수 있도록 하는 함수입니다.
/*
* 주소 정보가 IP address인지 domain명인지를 판단하기 위한 함수
* IP address이면 1 그렇지 않으면 0을 return 함
*/
static int is_ipaddr(const char *addr)
{
while(*addr) {
if(('0' <= *addr && *addr <= '9') || *addr == '.') {
addr++;
continue;
} else {
return 0;
}
}
return 1;
}
/*===================================================================================
* client socket을 생성하여 server socket으로 접속합니다.
* 파라미터:
* addr : 접속할 서버의 주소
* IP address 또는 domain 형식 (ex. 127.0.0.1 또는 downman.tistory.com)
* port : 접속할 port 번호
* return :
* 0이상 : 접속한 socket descriptor
* -1 : 오류발생, 상세 오류는 errno 전역변수 확인
===================================================================================*/
int TCPIPconnect(const char *addr, int port)
{
struct hostent *he;
struct sockaddr_in server_addr;
int sock;
memset(&server_addr, 0x00, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
if(is_ipaddr(addr)) { // IP 주소로 접속할려면...
server_addr.sin_addr.s_addr = inet_addr(addr);
} else { // domain명으로 접속하려면...
if((he = gethostbyname(addr)) == NULL) {
return -1;
}
memcpy(&server_addr.sin_addr.s_addr, he->h_addr, he->h_length);
}
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
return -1;
}
if(connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in)) == -1) {
close(sock);
return -1;
}
return sock;
}
int TCPIPserver(int port)함수
Serve socket을 생성하는 함수입니다. 내부적으로 socket(2), bind(2), listen(2)을 한 번에 처리합니다. 또한, port번호를 재 사용할 수 있도록 socket의 option을 설정합니다. 서버 프로그램이 종료후에 바로 다시 실행해야하는 경우에는 SO_REUSEADDR을 설정하지 해야 합니다. 그렇지 않으면 port가 사용중이라는 오류가 발생하여 1분 이상 socket생성을 할 수 없습니다. 이 option이 설정되었다고 해서 실행중인 서버가 있는 데, 2개를 실행할 수 있는 것은 아닙니다. 종류후 다시 실행을 바로 해야 하는 경우에만 바로 실행할 수 있도록 할 뿐입니다.
/*===================================================================================
* server socket을 생성합니다.
* 파라미터 :
* port : 서버 소켓의 port 번호
* return :
* 0 이상 : socket()/bind()가 완료된 server socket
* -1 : 오류발생, 상세 오류는 errno 전역변수 확인
===================================================================================*/
int TCPIPserver(int port)
{
int server_fd;
int reuse = 1;
struct sockaddr_in server;
if((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
return -1;
}
/*
* 프로그램을 restart해야하는 경우에 프로그램 종료후 바로 재실행하는 경우
* SO_REUSEADDR을 설정하지 않으면 1분이상 port 번호가 해제되지 않아서 bind 오류가 발생함.
*/
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = INADDR_ANY;
if(bind(server_fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1) {
return -1;
}
if(listen(server_fd, 50) == -1) {
return -1;
}
return server_fd;
}
int TCPIPaccept(int server_fd, struct sockaddr_in *client) 함수
Client의 요청을 받아드리고 새로운 socket을 생성합니다. 접속한 client의 정보(IP, port)를 얻습니다. client 파라미터를 NULL로 설정하면 client의 접속정보를 얻지 않습니다.
/*===================================================================================
* TCPIPaccept : client의 접속 요청을 받아들여 client와 연결된 새로운 socket을 생성합니다.
* 파라미터 :
* server_fd : TCPIPserver()가 return한 server socket descriptor
* client : 접속한 client의 IP 및 port 정보
* return :
* 0 이상 : client와 접속한 socket descirptor
* -1 : 오류발생, 상세 오류는 errno 전역변수 확인
===================================================================================*/
int TCPIPaccept(int server_fd, struct sockaddr_in *client)
{
int connected_fd;
socklen_t addr_len = 0;
if(client != NULL) {
addr_len = sizeof(struct sockaddr_in);
}
if((connected_fd = accept(server_fd, (struct sockaddr *)client, &addr_len)) == -1) {
return -1;
}
return connected_fd;
}
ssize_t TCPIPsend(int sockfd, const void *buf, size_t len, int flags) 함수
data를 전송합니다. signal발생하면 signal을 무시하고 재처리합니다.
/*===================================================================================
* TCPIPsend : 연결된 socket으로 데이터를 전송합니다.
* 파라미터 :
* sockfd : TCPIPconnect() 또는 TCPIPaccept()가 reutrn한 socket descriptor
* buf : 전송할 데이터
* len : 전송할 데이터 byte수
* flags : 일반적으로 0을 설정합니다.
* MSG_DONTROUTE, MSG_DONTWAIT, MSG_MORE, MSG_OOB 등을 사용할 수 있습니다.
* return :
* 0 이상 : 실제 전송된 데이터 byte수
* -1 : 오류발생, 상세 오류는 errno 전역변수 확인
===================================================================================*/
ssize_t TCPIPsend(int sockfd, const void *buf, size_t len, int flags)
{
ssize_t size;
while((size = send(sockfd, buf, len, flags)) == -1 && errno != EINTR );
return size;
}
ssize_t TCPIPrecv(int sockfd, void *buf, size_t len, int flags) 함수
data를 수신합니다. signal발생하면 signal을 무시하고 재처리합니다.
/*===================================================================================
* TCPIPrecv : 연결된 socket으로부터 데이터를 수신합니다.
* 파라미터 :
* sockfd : TCPIPconnect() 또는 TCPIPaccept()가 reutrn한 socket descriptor
* buf : 수신후 저장할 데이터 buffer
* len : 수신할 데이터 byte 수
* flags : 일반적으로 0을 설정합니다.
* MSG_DONTROUTE, MSG_DONTWAIT, MSG_MORE, MSG_OOB 등을 사용할 수 있습니다.
* return :
* 0 이상 : 실제 수신한 데이터 byte수
* -1 : 오류발생, 상세 오류는 errno 전역변수 확인
===================================================================================*/
ssize_t TCPIPrecv(int sockfd, void *buf, size_t len, int flags)
{
ssize_t size;
while((size = recv(sockfd, buf, len, flags)) == -1 && errno != EINTR );
return size;
}
int TCPIPclose(int sockfd) 함수
더 이상 사용하지 않을 socket을 close합니다.
/*===================================================================================
* TCPIPclose : 생성된 socket을 close합니다.
* 파라미터 :
* sockfd : TCPIPconnect(), TCPIPaccept(), TCPIPserver() 등으로 생성한 socket descriptor
* return :
* 0 : 정상적으로 close 됨.
* -1 : 오류 발생
===================================================================================*/
int TCPIPclose(int sockfd)
{
return close(sockfd);
}
see also : TCP/IP 통신 프로그램 Socket 통신 관련 Library
'C언어 응용 > TCP·IP' 카테고리의 다른 글
TCP/IP - 7. TCP/IP client 프로그램 Sample (0) | 2019.10.03 |
---|---|
TCP/IP - 6. 공통 라이브러리 만들기(정보 제공 함수) (0) | 2019.10.01 |
TCP/IP - 4. Client 처리 flow (0) | 2019.10.01 |
TCP/IP - 3. Server 처리 flow (0) | 2019.10.01 |
TCP/IP - 2. port 번호 범위 (2) | 2019.10.01 |