일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 리틀엔디언
- C언어
- Reverse Me
- 배열
- react native
- c언어 알고리즘
- 암호화폐
- 프론트엔드 개발자
- 네트워크 관리사 2급 필기
- abex crack me 5번문제
- 구조체
- 배열 정렬
- abex crack me 1번
- 알고리즘
- UDP daytime
- 레나 리버싱
- 구조체 함수
- 덧셈
- 메이플스토리 M 사전예약
- 안드로이드 백도어
- 리버싱
- 배열 탐색
- 오버워치
- sa 계정 비밀번호 변경
- 프로그래밍 언어론
- abex crack me 2번 문제풀이
- 마인크래프트
- 재밌는 모바일게임
- 빅엔디언
- 1.9.2
- Today
- Total
Gyejoong's Information
TCP/IP 프로토콜 소켓프로그래밍 - UDP로 daytime서비스 구현하기 본문
1. udp daytime 클라이언트 소스코드
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
void err_quit(const char *message);
void err_sys (const char *message);
#define MAXLINE 4096 /* max text line length */
int main(int argc, char *argv[])
{
if (argc != 2)
err_quit("usage: daytimeudpcli <IPaddress>");
// 비연결지향형 udp 소켓 생성 (socket)
int sockfd;
if ( (sockfd = socket(AF_INET,SOCK_DGRAM,0)) < 0)
err_sys("socket error");
// 서버에 더미(dummy) 데이터그램 전송 (sendto)
struct sockaddr_in servaddr;
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(13); /* daytime port */
int ret;
if ( (ret = inet_pton(AF_INET,argv[1],&servaddr.sin_addr)) < 0)
err_sys("inet_pton error");
else if (!ret)
err_quit("<IPaddress> error: not a valid network address string");
const char *m = "GIVE ME A DAYTIME STRING. :)";
if (sendto(sockfd,m,strlen(m),0,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)
err_sys("sendto error");
// 날짜/시간 문자열 수신 (recvfrom) 및 출력
int n;
char recvline[MAXLINE+1];
struct sockaddr_in fromaddr;
socklen_t len = sizeof(fromaddr);
if ((n = recvfrom(sockfd,recvline,MAXLINE,0,(struct sockaddr*)&fromaddr,&len)) < 0)
err_sys("recvfrom error");
if (memcmp(&servaddr,&fromaddr,len) != 0)
err_quit("reply from different host (failed)");
recvline[n] = 0; /* null terminate */
if (fputs(recvline,stdout) == EOF)
err_sys("fputs error");
// 접속 종료/프로그램 종료 (close, exit)
close(sockfd);
exit(0);
}
void err_quit(const char *message)
{
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
void err_sys (const char *message)
{
perror(message);
exit(1);
}
TCP소켓과 다른점은 UDP소켓은 비연결지향서비스라는 점이다. 그렇기 때문에 더미 데이터그램을 서버측에 보내야한다. 우선 UDP 소켓을 만들기 위해서 socket(AF_INET,SOCK_DGRAM,0) 이 부분에 SOCK_DGRAM으로 바꾸었다. 기존에 TCP 소켓은 SOCK_STREAM이였다. 그리고 TCP에서는 write와 read함수로 통신을 주고 받았다면
UDP에서는 sendto함수와 recvfrom함수를 쓰게된다. 그리고 connect는 하지않는다.(비연결)
sendto함수의 인자.
ssize _t sendto(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
recvfrom함수의 인자
ssize_t recvfrom(int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len);
그리고 연결이 안되있기 때문에 통신을 하기위해서는 memcmp라는 함수를 이용해서 보낼 서버의 주소와 더미데이터그램을 받은 서버의 주소와 일치해야만 출력을 하게 해야한다.
2. udp daytime 서버 소스코드
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <time.h>
void err_quit(const char *message);
void err_sys (const char *message);
#define MAXLINE 4096 /* max text line length */
int main(int argc, char *argv[])
{
// 비연결지향형 udp 소켓 생성 (socket)
int listenfd;
if ( (listenfd = socket(AF_INET,SOCK_DGRAM,0)) < 0)
err_sys("socket error");
// 서버주소와 소켓을 연결 (bind)
struct sockaddr_in servaddr;
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(13); /* daytime port */
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)
err_sys("bind error");
for ( ; ; ) {
// 클라이언트의 더미(dummy) 데이터그램 수신 (recvfrom)
char buff[MAXLINE];
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
if (recvfrom(listenfd,buff,MAXLINE,0,(struct sockaddr*)&cliaddr,&len) < 0)
err_sys("recvfrom error");
// 접속한 클라이언트의 정보를 화면에 출력
char cliname[INET_ADDRSTRLEN];
if ( inet_ntop(AF_INET,&cliaddr.sin_addr,cliname,sizeof(cliname)) )
printf("Handling client %s:%d\n",cliname,ntohs(cliaddr.sin_port));
else
err_sys("inet_ntop error");
// 클라이언트(cliaddr에 저장된)에게 daytime 문자열을 송신 (sendto)
time_t ticks = time(NULL);
snprintf(buff,sizeof(buff),"%.24s\r\n",ctime(&ticks));
if (sendto(listenfd,buff,strlen(buff),0,(struct sockaddr*)&cliaddr,len) < 0)
err_sys("sendto error");
} // 무한 반복 (for, while)
}
void err_quit(const char *message)
{
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
void err_sys (const char *message)
{
perror(message);
exit(1);
}
우선 UDP소켓이라하여도 bind는 해야한다. 서버주소와 소켓을 연결을 해야되기 때문이다. 대신에 listen과 accept는 하지 않는다. 연결이 되어있지 않기 때문이다.
우선 클라이언트 측에서 데이터그램을 먼저 보냈기때문에(sendto) 서버측에서는 데이터그램을 수신을 한다.(recvfrom) 그 후에 수신이 확인되면 daytime문자열을 만들어서 클라이언트측에 보낸다.(sendto)
이러면 UDP daytime서비스는 끝이난다.
다음은 연결된 UDP daytime클라이언트(connected-UDP daytime client)를 구현해보겠다.
3. connected-udp daytime 클라이언트 소스코드
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
void err_quit(const char *message);
void err_sys (const char *message);
#define MAXLINE 4096 /* max text line length */
int main(int argc, char *argv[])
{
if (argc != 2)
err_quit("usage: daytimeudpconcli <IPaddress>");
// 비연결지향형 udp 소켓 생성 (socket)
int sockfd;
if ( (sockfd = socket(AF_INET,SOCK_DGRAM,0)) < 0)
err_sys("socket error");
// 서버에 접속 (connect)
struct sockaddr_in servaddr;
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(13); /* daytime port */
int ret;
if ( (ret = inet_pton(AF_INET,argv[1],&servaddr.sin_addr)) < 0)
err_sys("inet_pton error");
else if (!ret)
err_quit("<IPaddress> error: not a valid network address string");
if (connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)
err_sys("connect error");
// 서버에 더미(dummy) 데이터그램 전송 (sendto -> write or send)
const char *m = "GIVE ME A DAYTIME STRING. :)";
if (write(sockfd,m,strlen(m)) < 0)
err_sys("write error");
// 날짜/시간 문자열 수신 (recvfrom -> read or recv) 및 출력
int n;
char recvline[MAXLINE+1];
if ((n = read(sockfd,recvline,MAXLINE)) < 0)
err_sys("read error");
recvline[n] = 0; /* null terminate */
if (fputs(recvline,stdout) == EOF)
err_sys("fputs error");
// 접속 종료/프로그램 종료 (close, exit)
close(sockfd);
exit(0);
}
void err_quit(const char *message)
{
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
void err_sys (const char *message)
{
perror(message);
exit(1);
}
우선 소켓은 UDP 소켓을 만들고, connect를 한다. 이유는 연결된 udp 소켓이기 때문이다. 연결 되었지만 UDP소켓이므로 더미데이터그램을 전송해준다. 하지만 연결이 되어있으므로 write를 쓰기로 했다. 그리고 마찬가지로 문자열을 수신할 때도 recvfrom 대신에 read를 썼다. 연결이 안되어있을 때는, memcmp함수로 주소끼리 비교해주었지만, 연결된 상태에서는 주소가 다를 수가 없기 때문에 memcmp함수로 주소를 비교하지 않아도 된다.
'Study > Socket programming' 카테고리의 다른 글
리틀엔디언과 빅엔디언의 차이점 (0) | 2016.10.05 |
---|---|
소켓프로그래밍 서버 코드 (daytime, echo) (0) | 2016.10.05 |
소켓 프로그래밍 클라이언트 코드(daytime,qotd,echo,finger) (0) | 2016.10.05 |