● 헤더파일
/*
* tcpecho.c
* TCP Echo Client 프로그램
* gcc -o tcpechoc hostname port 번호
* 사용법 : tcpechoc hostname port 번호
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
● struct hostent *hp, *gethostbyname();
- hostent는 <netdb.h>에 있다.
struct hostent
{
char *h_name; //공식 도메인 이름
char **h_aliases; //공식 이외 도메인 이름들
int h_addrtype; //주소정보 체계(IPv4: AF_INET, IPv6: AF_INET6)
int h_length; //IP주소의 크기를 담는다. (IPv4는 4)
char **h_addr_list; //도메인 이름에 대한 IP주소가 정수 형태로 반환될 때 이 멤버 변수를 사용
}
- gethostbyname 의 결과값 : 주소값
● 소켓 생성 - socket()
if (argv < 3) {
printf("Usage: tcpechoc hostname portnumber\n");
exit(0);
}
/*
* 스트림 소켓 생성 (소켓 패밀리, 소켓 종류, 하위계층 프로토콜)
* 새로운 소켓 디스크립터를 리턴(sockfd)
*/
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0) < 0) {
printf("client: can't open stream socket");
exit(1);
}
printf("SOCKET CREATED sockfd = %d\n", sockfd);
● Echo 서버 실별자 구하기 (1) - Family
- Family : AF_INET 또는 PF_INET
- IP 주소 : 220.100.50.20
- 포트번호 : 8888
bzero((char 8)&serv_addr, sizeof(serv_addr));
/*
* 서버 정보 구하고, 채우기
* [서버소켓 패밀리, 서버 IP주소, 서버프로그램식별자(포트번호)]
*/
/* 패밀리 정보를 serv_addr에 저장 */
serv_addr.sin_family = AF_INET;
/*
* 서버 호스트의 IP 주소 및 관련 정보 구하기
* gethostbyname() : name resolver라고 함
* /etc/hosts 파일을 검색하고, 없으면 Name Server에게 요청
*/
hp = gethostbyname(argv[1]);
if (hp == (struct hostent *) 0) {
fprintf(stderr, "%s: unknown host\n", argv[1]);
exit(1);
}
/* 구한 서버 호스트 정보를 serv_addr에 저장 */
bcopy((char *) &serv_addr.sin_addr, (char *) hp->h_addr_list[0], hp->h_length);
● gethostbyname()
=> 도메인 이름(호스트 이름)을 IP 주소로 변환하는 함수이다. 이 함수는 주로 IPv4 주소를 반환하며 IPv6 주소는 지원하지 않는다.
- 함수 선언
#include <netdb.h>
struct hostent *gethostbyname(const char *name);
○ name : 변환할 호스트 이름을 나타내는 문자열이다.
○ 반환값 : 'hostent' 구조체를 가리키는 포인터이다. 실패하면 'NULL'을 반환한다.
● Echo 서버 식별자 구하기 (1) - Port 번호
/* 서버프로그램 식별자(포트번호)는 이미 알고 있어야 함*/
/* 서버 소켓의 포트 값을 serv_addr에 저장 */
serv_addr.sin_port = htons(atoi(argv[2]));
● connect() - TCP에게 접속 설정 요청
/* TCP에게 접속 설정 요청 connect() */
printf("CONNECTING....\n");
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr) == -1) {
printf("client: connect error\n");
exit(1);
}
printf("접속 성공!!! \n");
● Local Port 번호 생성
○ echo server의 포트번호는
- /etc/services에 저장된 well-known port에 의해 미리 지정되거나
ex) echo 서버는 7
- 사용자가 직접 지정해야 함
ex) 8888
○ echo client의 포트번호는
- 응용 프로세스에서 접속요청이 발생하면 TCP는 현재 사용하고 있지 않은 local computer에서 유일한(unique) 포트번호를 할당함(dynamic)
● fgets() - 키보드로 부터 입력
/* 키보드 입력 대기 : stdin(standard input) */
pirntf("입력 : ");
if (fgets(buf, sizeof(buf), stdin) == NULL) {
exit(0);
}
● write()/send() - 데이터 전송 // read()/recv() - 데이터 수신
nbyte = strlen(buf);
/* 에코 서버로 메시지 전송 */
/* TCP에게 데이터 전송 요청 */
if (write(sockfd, buf, nbyte) == -1) {
printf("Echo Client: data trafer error\n");
exit(1);
}
printf("수신: ");
/* TCP에게 데이터 수신 요청 */
if((nbyte = read(sockfd, buf, MAXLINE) < 0) {
perror("read fail");
exit(0);
}
buf[nbyte] = 0;
/* 수신된 에코 메시지 화면 출력 */
printf("%s", buf);
● close() - TCP에게 접속종료 요청
/* 소켓 닫기 : TCP에게 접속 종료 요청 */
close(sockfd);
printf("CLOSED\n");
return (0);
}
'인터넷과 소켓프로그래밍' 카테고리의 다른 글
TCP 에코 서버 (계속) (0) | 2024.07.28 |
---|---|
소켓 개요 및 TCP 에코 서버 (0) | 2024.07.26 |
소켓 프로그래밍을 위한 알아야할 기능들 (0) | 2024.07.25 |
포트번호와 주소변화 (0) | 2024.07.24 |
서브넷 및 IPv6 주소 (3) | 2024.07.23 |