본문 바로가기

Network/초급 TCP/IP socket

07. TCP 에코 서버 소켓( (TCP ECHO SERVER SOCKET)

TCP에코 클라이언트에 이어 TCP에코 서버를 구현해 보았습니다

TCPEchoServer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "practical.h"

/* 연결 요청을 대기 할 수 있는 최대수 */
static const int MAXPENDING = 5;

int main (int argc, char * argv[])
{
  int clntSock;  
  int servSock; //서버 소켓 식별자
  char clntName[INET_ADDRSTRLEN];
  in_port_t servPort = atoi(argv[1]); //첫번째 인자 : 지역포트
  
  struct sockaddr_in servAddr;
  struct sockaddr_in clntAddr;
  
/* 명령어 인자의 개수 */
  if(argc != 2)
    DieWithUserMessage("Parameter(s)","<Server Port>");
/* 소켓생성 */  
  if((servSock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
    DieWithSystemMessage("socket(s) failed");
/* 지역 주소 구조체 생성 */
  memset(&servAddr,0,sizeof(servAddr));
  servAddr.sin_family = AF_INET;
  servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servAddr.sin_port = htons(servPort);
/* 지역 주소에 바인드 */
  if(bind(servSock, (struct sockaddr*) &servAddr,sizeof(servAddr))<0)
    DieWithSystemMessage("bind() failed");
/* 소켓이 들어오는 요청을 처리 할수 있도록 설정 */
  if(listen(servSock, MAXPENDING)<0)
    DieWithSystemMessage("bind() failed");
  for(;;) // 무한실행
  {
    /* 클라이언트 주소 구조체의 크기 설정 */
    socklen_t clntAddrLen = sizeof(clntAddr);
    /* 클라이언트의 연결을 기다림 */
    clntSock = accept(servSock, (struct sockaddr *) &clntAddr,&clntAddrLen);

    if(clntSock <0)
       DieWithSystemMessage("accept() failed");

    //clntSock가 클라이언트와 연결됨
    
    clntName[INET_ADDRSTRLEN]; //클라이언트 주소를 담기위한 문자열
    if(inet_ntop(AF_INET, &clntAddr.sin_addr.s_addr,clntName,
          sizeof(clntName))!=NULL)
      printf("Handling client %s/%d\n", clntName, ntohs(clntAddr.sin_port));
    else
      puts("unable to get client address");

    HandleTCPClient(clntSock);
  }
}

DieWithUserMessage.c 파일(오작동시 에러메세지를 출력!!)

-HandleTCPClient추가
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#define BUFSIZE 30

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);
}

void HandleTCPClient(int clntSocket)
{
  char buffer[BUFSIZE];
  ssize_t numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0);

  if (numBytesRcvd < 0)
    DieWithSystemMessage("recv() failed");

  while(numBytesRcvd > 0)
  {
    ssize_t numBytesSent = send(clntSocket, buffer, numBytesRcvd,0);
    if(numBytesSent < 0)
      DieWithSystemMessage("send() failed");
    else if(numBytesSent != numBytesRcvd)
      DieWithUserMessage("send()","sent unexpected number of bytes");

    numBytesRcvd = recv(clntSocket, buffer, BUFSIZE,0);
    if(numBytesRcvd <0)
      DieWithSystemMessage("recv() failed");

  }
  close(clntSocket);
}


practical.h 헤더파일 처리하기
void DieWithUserMessage(const char *msg, const char *detail);
void DieWithSystemMessage(const char *msg);
void HandleTCPClient(int clntSocket);



컴파일(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.접속성공 2000
./TCPEchoServer 2000


결과