2019. 7. 22. 00:34ㆍ드론

TCP는 연결 기반의 신뢰성 있는 통신 방식으로 FTP, 메일, 웹 서비스 등 인터넷을 이용한 다양한 서비스에서 사용되고 있다. 신뢰성을 추구하다보니 UDP보다는 복잡한 절차와 방식으로 서버와 클라이언트가 구현된다
bind() 하는 과정은 UDP 서버와 동일하다. UDP와는 다르게, TCP는 클라이언트가 3 Way Handshaking을 통해서 서버에 접속하기 때문에, 클라이언트의 대기를 처리하는 큐가 필요하다. 이를 위해 listen 함수를 오해 대기 큐를 설정하고, accept를 통해서 클라이언트의 접속을 기다릴 수 있다. 참고로 3 Way Handshaking은 신뢰성 있는 연결을 위해 3번의 패킷 교환(SYN, SYN/ACK, ACK)으로 연결하는 동작을 의미한다
TCP 클라이언트는 connect 함수를 이용해서 서버에 접속하게 되고, 이후에 send와 recv 함수를 사용하거나 read와 write를 통해서 통신할 수 있다. UDP와는 달리, 이미 서버에 접속해 있으므로 데이터를 보낼 때 서버의 정보를 사용할 필요가 없다
클라이언트 서비스의 준비가 완료되었다면, 서버에서 클라이언트의 접속을 처리해야 할 메모리 공간이 필요하게 된다. 이 때 listen 함수를 통해 대기 큐를 설정할 수 있다. 함수 원형은 다음과 같은데,
int listen(int sockfd, int backlog)
두 번째 인자는 다음과 같이 설명되어 있다
The backlog argument defines the maximum length to which the queue of pending connections for sockfd may grow.
즉 연결 요청을 할 수 있는 클라이언트 소켓 수를 의미하고, 이를 넘어간다면 연결 시도가 거부된다
그리고 마지막으로 accept에서는 접속한 클라이언트 정보를 얻기 위해 주소 구조체를 사용한다. 인자를 받아오고 나서는, 구조체 필드 중 IP와 포트는 빅 엔디안으로 사용되기 때문에 인코딩 변환이 필요하다. 그리고 accept는 성공했을 시 접근한 클라이언트의 fd를 반환한다
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <arpa/inet.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#define TCP_PORT 5100 | |
#define BUF_SIZE 256 | |
int main(int argc, char **argv) | |
{ | |
int ssock; | |
int clen; | |
struct sockaddr_in servaddr; | |
char buf[BUF_SIZE]; | |
if(argc < 2) { | |
printf("Usage :%s IP_ADDRESS\n", argv[0]); | |
return -1; | |
} | |
if((ssock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { | |
perror("socket"); | |
return -1; | |
} | |
memset(&servaddr, 0, sizeof(servaddr)); | |
servaddr.sin_family = AF_INET; | |
// 문자열을 IP 주소 포맷으로 바꿔주는 과정 | |
servaddr.sin_addr.s_addr = inet_addr(argv[1]); | |
// htons의 매개변수는 uint32_t 혹은 uint16_t로, 만일 argv로 받을 때 atoi 처리를 해야만 한다 | |
servaddr.sin_port = htons(TCP_PORT); | |
clen = sizeof(servaddr); | |
if(connect(ssock, (struct sockaddr *)&servaddr, clen) < 0) { | |
perror("connect()"); | |
return -1; | |
} | |
fgets(buf, BUF_SIZE, stdin); | |
if(write(ssock, buf, BUF_SIZE) <= 0) { | |
perror("write"); | |
return -1; | |
} | |
memset(buf, 0, BUF_SIZE); | |
if(read(ssock, buf, BUF_SIZE) <= 0) { | |
perror("read"); | |
return -1; | |
} | |
printf("Received data : %s", buf); | |
close(ssock); | |
return 0; | |
} |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <arpa/inet.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#define TCP_PORT 5100 | |
#define BUF_SIZE 256 | |
int main(int argc, char **argv) | |
{ | |
int ssock; | |
socklen_t clen; | |
int n; | |
struct sockaddr_in servaddr, cliaddr; | |
char buf[BUF_SIZE] = "Hello World"; | |
if((ssock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) { | |
perror("socket()"); | |
return -1; | |
} | |
memset(&servaddr, 0, sizeof(servaddr)); | |
servaddr.sin_family = AF_INET; | |
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); | |
servaddr.sin_port = htons(TCP_PORT); | |
if(bind(ssock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { | |
perror("bind"); | |
return -1; | |
} | |
/* 동시에 접속하는 클라이언트의 처리를 위한 대기 큐를 설정 */ | |
if(listen(ssock, 8) < 0) { | |
perror("listen"); | |
return -1; | |
} | |
clen = sizeof(cliaddr); | |
while(1) { | |
/* blocking 상태로 소켓이 연결될 때까지 대기한 후 생성 */ | |
int csock = accept(ssock, (struct sockaddr *)&cliaddr, &clen); | |
printf("Client is connected : %s\n", inet_ntoa(cliaddr.sin_addr)); | |
if((n = read(csock, buf, BUF_SIZE)) <= 0) { | |
perror("read"); | |
} | |
printf("Received data : %s\n", buf); | |
// 서버에서 write/read를 할 때의 fd는 클라이언트 fd | |
if(write(csock, buf, n) <= 0) { | |
perror("write"); | |
} | |
close(csock); | |
} | |
close(ssock); | |
return 0; | |
} |
클라이언트는 호스트와의 연결을 종료하기 위해 close 함수를 사용해 소켓을 닫았다. 출력 스트림을 종료하면 소켓을 통해 EOF 메세지가 전달되는데, EOF 전송으로 데이터 전송의 끝을 알릴 수 있다. EOF 전송 시 상대 호스트의 수신 함수는 0을 반환하게 된다
[출처] 사물인터넷을 위한 리눅스 프로그래밍
'드론' 카테고리의 다른 글
SOCK_DGRAM은 read/write 사용할 수 없는 이유 (0) | 2019.07.22 |
---|---|
동작 중인 포트 조회해서 지우기 (0) | 2019.07.22 |
서버 소켓 개방 시 INADDR_ANY의 의미 (0) | 2019.07.22 |
UDP 네트워크 프로그래밍 - 2 (0) | 2019.07.21 |
UDP 네트워크 프로그래밍 - 1 (0) | 2019.07.21 |