클라이언트에 메세지를 입력하고 서버로부터 되돌아온 메세지를 화면에 출력합니다
참고1) 실행
./실행파일 IP주소 메세지 의 형태로 합니다
참고2)linux에코 설정 setup
설정후 리셋해준다
IPv4 TCP 클라이언트
중요한 4가지 단계
1.socket()을 이용하여 TCP소켓을 생성
2.connect()를 이용하여 서버와의 연결을 설정
3.send(),recv()를 이용하여 통신을 수행
4.close()를 이용하여 연결을 종효
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<unistd.h>
#include
<sys/types.h>
#include
<sys/socket.h>
#include
<netinet/in.h>
#include
<arpa/inet.h>
#include
"practical.h"
#define
BUFSIZE 30
int
main(int argc, char *argv[])
{
char *servIP=argv[1];
char *echoString=argv[2];
int sock;
int renVal;
char buffer[BUFSIZE]; //
입/출력 버퍼
in_port_t servPort;
unsigned int totalBytesRcvd = 0; //
수신한 문자 개수
size_t echoStringLen;
ssize_t numBytes;
struct sockaddr_in servAddr;
int rtnVal;
/*
명령어 인자의 정확한 갯수 확인*/
if(argc < 3 || argc > 4)
DieWithUserMessage("Parameter(s)","<Server Address><Echo Word>[<Server Port>]");
/*
세 번째 인자(선택)) : 서버 포트(숫자형식), 7을 사용*/
servPort = (argc == 4) ? atoi(argv[3]) : 7;
/*TCP
를 사용하여 안정된 스트림 소켓 생성*/
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock < 0)
DieWithSystemMessage("socket() failed");
/*
서버주소 구조체 생성*/
memset(&servAddr, 0 ,sizeof(servAddr)); //
구조체 초기화
servAddr.sin_family = AF_INET; //IPv4
주소 패밀리
/*
주소변화*/
rtnVal = inet_pton(AF_INET,servIP, &servAddr.sin_addr.s_addr);
if(rtnVal == 0)
DieWithUserMessage("inet_pton() failed","invalid address string");
else if(rtnVal <0)
DieWithSystemMessage("inet_pton() failed");
/*
서버포트*/
servAddr.sin_port = htons(servPort);
/*
에코 서버에 연결 설정*/
if(connect(sock, (struct sockaddr *) &servAddr, sizeof(servAddr))<0)
DieWithSystemMessage("connect() failed");
/*
입력받은 문자열의 길이*/
echoStringLen = strlen(echoString);
/*
서버에 에코 문자열 전송*/
numBytes = send(sock, echoString, echoStringLen, 0);
if(numBytes < 0)
DieWithSystemMessage("send() failed");
else if(numBytes != echoStringLen)
DieWithUserMessage("send()", "send unexpected number of bytes");
/*
서버로 부터 동일한 문자열 수신*/
fputs("Received : ", stdout); //
돌려받은 에코 문자열 출력을 위한 설정
while(totalBytesRcvd < echoStringLen)
{
numBytes = recv(sock, buffer, BUFSIZE - 1, 0);
if(numBytes < 0)
DieWithSystemMessage("recv() failed");
else if(numBytes == 0)
DieWithUserMessage("recv()","connection closde prematurely");
totalBytesRcvd += numBytes; ); //
총 받은 크기를 기록
buffer[numBytes] = '\0'; //
널 문자를 추가하여 문자열 완성
fputs(buffer,stdout); //
에코 버퍼를 출력
}
fputc('\n',stdout); //
마지막으로 개행문자 출력
close(sock);
exit(0);
return 0;
}
동작순서 요약
1. 응용프로그램 초기 설정 및 파라미터 파싱
2. TCP소켓 생성 AF_INET SOCK_STREAM 0 의 형태이고 에러처리 DieWithUserMessage()
함수사용
3. 주소 준비 및 연결 설정
*서버의 주소를 담기 위해여 sockaddr_in 구조체를 준비 / memset()구조체를 초기화
*inet_pton의 함수로 구조체를 체움
*connect는 구조체sockaddr_in이 가리키는 주소로 연결 시도
4. 에코 문자열을 서버에 보냅니다 send()이용
5. 에코 서버의 응답수신 recv()를 이용
*버퍼출력 : null문자로 끝나는 일반문자열을 다루는 fputs()를 사용하여 출력
*개행문자 줄바꿈
참고)printf 의 경우 심각한 보안상이 허점으로 인하여 잘 사용하지 않습니다
practical.h 헤더파일 처리하기
DieWithUserMessage(const char *msg, const char *detail);
void
DieWithSystemMessage(const char *msg);
DieWithUserMessage.c
파일(오작동시 에러메세지를 출력!!)
#include <stdio.h>
#include
<stdlib.h>
void
DieWithUserMessage(const char *msg, const char *detail)
{
fputs(msg,stderr);
fputs(":",stderr);
fputs(detail, stderr);
fputc('\n',stderr);
exit(1);
}
void
DieWithSystemMessage(const char *msg)
{
perror(msg);
exit(1);
}
컴파일(gcc) 순서
1)gcc –o TCPEchoClient4 TCPEchoClient4.c
2)gcc –c DieWithMessage DieWithMessage.c
3)gcc –o TCPEchoClient4 TCPEchoClient4.c DieWithMessage.o
실행
./TCPEchoClient4 127.0.0.7 안녕하세요!!
'Network > 초급 TCP/IP socket' 카테고리의 다른 글
08. TCP / UDP 데이터 전송 경계 확인 (0) | 2011.07.11 |
---|---|
07. TCP 에코 서버 소켓( (TCP ECHO SERVER SOCKET) (0) | 2011.07.08 |
05. UDP통신흐름 (0) | 2011.07.05 |
04. Server / Client TCP통신흐름 리눅스 프로그래밍 (0) | 2011.07.04 |
03. 주소의 표현 방식3가지와 전환 (0) | 2011.07.01 |