TCP소켓의 흐름에서 connect()를 사용하여 지정된 주소로 연결을 시도합니다 전화를 걸기위해 번호를 누르는것과 비슷한데 원형은 이렇습니다

int connect(int socket, const struct sockaddr *foreignAddress, socklen_t addressLength)

소켓을 통해 앞으로 전송 할 데이터그램의 목적지 주소를 고정하기 위해서 UDP소켓상에서 connect()을 사용하는 것이 가능합니다 연결이 되면 목적지를 저장할 필요가 없기 때문에 sendto() 대신 send()를 이용하면 됩니다 연결이 이루어진 지정한 주소로만 데이터의 송수신이 가능합니다 

 



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

void error_handling(char * message);

int main()
{
  int sock;
  char message[30];
  int str_len;
  
  struct sockaddr_in serv_addr;
  
  sock =  socket(PF_INET, SOCK_DGRAM, 0);

  memset(&serv_addr, 0sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  serv_addr.sin_port =  htons(9190);
  
  connect(sock,(struct sockaddr*)&serv_addr, sizeof(serv_addr));

  while(1)
  {
    fputs("전송할 메시지를 입력하세요(q to quit) : ", stdout);
    fgets(message, sizeof(message), stdin);

    if( !strcmp(message,"q\n")) break;
  
    write(sock, message, strlen(message));
    
    str_len = read(sock,message,sizeof(message)-1);
    message[str_len] = 0;
    printf("서버로 부터 수신된 메세지  : %s \n",message);
  }

  close(sock);
  return 0;
}


결과>>



위 프로그램은 server를 동작시키지 않고도 message[]에 입력된 데이터를 출력하기 때문에 server에서 보내온 메세지를 확인 할수 없습니다
server에서 보내오는 메세지를 저장할  message2[]를 선언하여 서버로 부터 보내온 메세지를 저장하고 출력합니다

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

void error_handling(char * message);

int main()
{
  int sock;
  char message[30];
  char message1[30];
  int str_len;
  
  struct sockaddr_in serv_addr;
  
  sock =  socket(PF_INET, SOCK_DGRAM, 0);

  memset(&serv_addr, 0sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  serv_addr.sin_port =  htons(9190);
  
  connect(sock,(struct sockaddr*)&serv_addr, sizeof(serv_addr));

  while(1)
  {
    fputs("전송할 메시지를 입력하세요(q to quit) : ", stdout);
    fgets(message, sizeof(message), stdin);

    if( !strcmp(message,"q\n")) break;
  
    write(sock, message, strlen(message));
    
    str_len = read(sock,message1,sizeof(message)-1);
    message1[str_len] = 0;
    printf("서버로 부터 수신된 메세지  : %s \n",message1);
  }

  close(sock);
  return 0;
}



결과>>


sever를 실행하지 않고 client만 실행했을 경우 "서버로 부터 수신된 메세지"에 아무것도 출력되지 않은 것을 알수있습니다
Posted by mantwo
TCP or UDP기반의 데이터 전송의 경계를 확인하여 보겠습니다

설명)
UDP에 비해 TCP의 장점은
   1. 신뢰할수있다
   2. 데이터 누락 처리가 가능하다
   3. 데이터 순서바낌처리가 가능하다
   4. 데이터 경계가 없다

등이 있습니다

여기에선 4 데이터 경계가 없는  TCP와 경계가 있는 UDP에 대헤서 살펴 보도록 하겠습니다

일단 아래 그림을 참고하여 TCP의 결과는


 

보낸 문자열을 서로 구분하지 않고 2개씩 3개씩 혹은 몰아서 한꺼번에 recv에서 수신버퍼로 처리가 가능합니다
데이터의 경계가 없어서 넘어온 데이터는 송신버퍼에 쌓인후 순서대로 수신버퍼로 보내지게 됩니다



하지만 UDP의 경우 아래 그림을 참고하시면

보내는 수신버퍼와 받는 송신버퍼가 1:1임을 알수있습니다
ABC를 보내고 DEF 를 보내면 ABC DEF가 아닌
ABC를 처리하고 DEF를 처리하게 됩니다

앞에서 구형하였던 TCP Echo client 와 server는 UDP의 이러한 점을 모방하여 구현해놓은것입니다 


1)TCP


TCP Client 소스

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

void error_handling(char * message);

int main()
{
  int sock;
  int str_len,i;
  struct sockaddr_in serv_addr;
  
  char msg1[] = "Hello Everybody~";
  char msg2[] = "I am so Happy!";
  char message[10];

  sock =  socket(PF_INET, SOCK_STREAM, 0);
  if(sock == -1)
    error_handling("socket() error");

  memset(&serv_addr, 0sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  serv_addr.sin_port =  htons(9190);

  if ( connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
    error_handling("connect() error");

  write(sock , msg1, strlen(msg1));
  write(sock , msg2, strlen(msg2));
  
  sleep(3);

  for(i=0;i<4;i++)
  {
    str_len = read(sock,message,sizeof(message)-1);
    message[str_len] = 0;
    printf("message from server : %s \n", message);
  }
  
  close(sock);
  return 0;
}

void error_handling(char * message)
{
  fputs(message, stderr);
  fputc('\n', stderr);
  exit(1);
}



 TCP Server

#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 BUFSIZE 100

void error_handling(char * message);

int main()
{
  int serv_sock;
  int clnt_sock;
  struct sockaddr_in serv_addr;
  struct sockaddr_in clnt_addr;
  int clnt_addr_size;
  char message[BUFSIZE];
  int str_len;

  serv_sock =  socket(PF_INET, SOCK_STREAM, 0);
  if(serv_sock == -1)
    error_handling("socket() error");

  memset(&serv_addr, 0sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  serv_addr.sin_port =  htons(9190);

  if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
    error_handling("bind() error");

  if(listen(serv_sock,5== -1)
    error_handling("listen() error");
  
  clnt_addr_size = sizeof(clnt_addr);
  clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);

  if(clnt_sock == -1)
    error_handling("accept() error");

  sleep(5);
  str_len = read(clnt_sock,message,BUFSIZE);
  write(clnt_sock, message, sizeof(message));

  close(clnt_sock);
  return 0;
}

void error_handling(char* message)
{
  fputs(message, stderr);
  fputc('\n', stderr);
  exit(1);
}


결과>>


데이터의 경계가 없이 9바이트(sizeof(serv_addr)) == -1)크기에 처리한 순서대로 전송되어온것을 확인 할 수 있습니다!


2)UDP

UDP Client

#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 BUFSIZE 30

void error_handling(char * message);

int main()
{
  int sock;
  int str_len,addr_size,i;
  char message[BUFSIZE];
  
  struct sockaddr_in serv_addr;
  struct sockaddr_in from_addr;
  
  char msg1[] = "Good";
  char msg2[] = "Afternoon";
  char msg3[] = "Everybody!";

  sock =  socket(PF_INET, SOCK_DGRAM, 0);
  if(sock == -1)
    error_handling("socket() error");

  memset(&serv_addr, 0sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  serv_addr.sin_port =  htons(9190);

  sendto(sock , msg1, strlen(msg1),0,(struct sockaddr*)&serv_addr, sizeof(serv_addr));
  sendto(sock , msg2, strlen(msg2),0,(struct sockaddr*)&serv_addr, sizeof(serv_addr));
  sendto(sock , msg3, strlen(msg3),0,(struct sockaddr*)&serv_addr, sizeof(serv_addr));
  
  sleep(3);

  for(i=0;i<3;i++)
  {
    addr_size = sizeof(from_addr);
    str_len = recvfrom(sock,message,BUFSIZE,0,(struct sockaddr*)&from_addr, &addr_size);
    message[str_len] = 0;
    printf("서버로 부터 수신된 %d 차 메세지  : %s \n", i, message);
  }
  close(sock);
  return 0;
}

void error_handling(char * message)
{
  fputs(message, stderr);
  fputc('\n', stderr);
  exit(1);
}


UDP Server 

#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 BUFSIZE 30

void error_handling(char * message);

int main()
{
  int serv_sock;
  char message[BUFSIZE];
  int str_len, num = 0;
  
  struct sockaddr_in serv_addr;
  struct sockaddr_in clnt_addr;
  int clnt_addr_size;
  
  serv_sock =  socket(PF_INET, SOCK_DGRAM, 0);
  if(serv_sock == -1)
    error_handling("socket() error");

  memset(&serv_addr, 0sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  serv_addr.sin_port =  htons(9190);

  if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
    error_handling("bind() error");

  sleep(5);
  
  while(1)
  {
    clnt_addr_size = sizeof(clnt_addr);
    sleep(1);
    str_len = recvfrom(serv_sock,message,BUFSIZE,0,(struct sockaddr*)&clnt_addr, &clnt_addr_size);
    printf("수신번호 : %d \n", num++);
    sendto(serv_sock , message, str_len,0,(struct sockaddr*)&clnt_addr, sizeof(clnt_addr));
  }
  return 0;
}

void error_handling(char* message)
{
  fputs(message, stderr);
  fputc('\n', stderr);
  exit(1);
}

 

결과>>



전송된 문자열을 보면 단어별로 의미에 맞게 끝을 확인 할 수 있게 전송되었음을 알수 있습니다

Posted by mantwo
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


결과


Posted by mantwo

 에코 서버/클라이언트: 서버/클라이언트가 전송해 주는 데이터를 그대로 되돌려 전송해 주는 기능의 서버/클라이언트를 말합니다

 

클라이언트에 메세지를 입력하고 서버로부터 되돌아온 메세지를 화면에 출력합니다

 

참고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 - 10);

    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 헤더파일 처리하기

void 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 안녕하세요!!

Posted by mantwo

참고!!
TCP :
연결형(연결요청,허락)(connect, accept, listen)등의 과정이 있다

UDP : 비연결형으로(연결요청,허락)(connect, accept, listen)등의 과정이 없다

 

연결형서버 (TCP소켓)

비연결형서버( UDP소켓)

 

interactive 서버 : 클라이언트에 서비스 요구를 순서대로 처리

concurrent 서버 : 클라이언트가 동시에 요청을 할때 동시에 처리를 한다

 

 

UDP 통신흐름

 

server                             client

서버소켓생성                    클라이언트소켓생성
           
socket(PF_INET,SOCK_DGRAM,0);


소켓에 주소할당

bind()

 

/ 수신                            / 수신

        sendto(),recvfrom()사용

 

클라이언트 소켓닫기           클라이언트 소켓닫기


 

UDPclient


UDPserver


결과

Posted by mantwo

TCP/IP통신의 흐름을 리눅스 프로그래밍을 통하여  살펴보도록하겠습니다

참고1)구조체

sockaddr_in구조체

{

ip주소, 포트번호, 설정

}

 

참고2)server프로그램


공통 socket생성

Socket()
응용프로그램이 이를 통해 데이터를 송수신할수 있는 추상화된 개념

#include <sys/types.h>
#include <sys/socket.h>

int socket(int domain, int type, int protocol);
    socket(PF_INET,SOCK_STREAM,0);


int domain : 소켓의 통신 영역을 결정합니다 AF_INET(IPv4)(IPv6) PF_INET 

int type : 생성될 소켓이 어떠한 방식으로 데이터를 전송할지를 결정합니다 SOCK_STREAM /DGRAM

int protocol : 사용될 종단 간 프로토콜을 구체적으로 명시합니다 주로 0을 넣으면 앞의 인자를 확인하여 자동으로 선택을 합니다



Server 서버 (위 그림 참고)

 

소켓주소할당 bind()

: sickaddr_in구조체(해당주소와 포트)를 소켓에 연결하는것

간단하게 소켓에 주소를 할당하는 함수다

 

int bind(int socket, struct sockaddr *localAddress, socklen_t addressSize)

bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))


1)
     
소켓식별자 serv_sock


2)
     
구조체의 주소(포인터로 접금) (struct sockaddr*)&serv_addr


3)
     
구조체의 크기 sizeof(serv_addr)


 
와일드카드 주소(INADDR_ANY)?

:지정한 아무 주소에나 연결된다는 의미이고 서버의 경우 어떤 호스트의 주소로 들어오는 연결이라도 받아들인다는 의미

 

연결대기 listen()

:주소 연결(bind)를 하게 되면 서버 소켓은 주소를 가지게 된다 서버 소켓으로 하여금 클라이언트로부터 연결을 대기하게 하기 위해서는 또하나의 과정을 하부 프로토콜 내부가 수행해야 되는데 listen을 통하여 가능하다

 

간단하게 말해서 연결요청을 대기모드로 설정하는것

 

중요한점은 주소와 포트에 연결되고 대기를 하고 있는 코세은 실제로 절대 송수신에 사용되지 않으며 각 클라이언트를 연결하기 위한 새로운 소켓을 획득하기 위한 수단으로만 사용한다

 

int listen(int socket, int queueLimit)

    listen(serv_sock, 5)

 

queue : 먼저 들어간 것이 먼저 처리된다는 의미

int queueLimit 연결을 기다리는 클라이언트의 대수를 뜻함

listen(  ,5) 연결요청을 하는 클라이언트의 최대 갯수를 5개로 함

 

5개의 연결대기 클라이언트로 가능

listen(  ,1) 1개의 클라이언트만 가능하고 통신중 다른 클라이언트가 들어와도 대기하지 못하다 튕기게 된다

 

소켓 생성 accept()

:연결을 위해 새로운 소켓을 생성한다

 

accept함수의 기본형은 socket descript(같다)이다

 

int accept(int socket, struct sockaddr *clientAddress, socklen_t*addressLength)

   accept(serv_sock,(struct_sockaddr*)&clntaddr, &clnt_addr_size);

클라이언트의 주소를 담은 구조체와 길이

 

Server 동작순서

 

server socket생성

ò

sockadd_in 구조체에 주소설정(ip,port)

ò

bind() 소켓에 구조체 값 할당(nonblocking)

ò

listen() 서버소켓에 대기모드, 클라이언트 최대 접속수 설정하고 나옴(nonblocking)

ò

accept() 연결요청한 클라이언트와 통신할 송수신용 소켓생성(blocking)

  -연결 요청이(connect)들어 올때까지 대기함

 

 

 참고3) client 프로그램

   

Client 클라이언트(위 그림 참고)

 

서버와연결 connect()

:서버는 클라이언트가 접속하기를 수동적으로 기다리는데 반해 클라이언트는 연결을 직접시도한다

 

int connect(int socket, const struct sockaddr *foreignAddress, socklen_t addressLength)

connect(sock, (struck sockaddr*)&serv_addr, sizeof(serv_addr))

*bind()와 비슷하게 생겼다

 

client 동작순서

 

socket() 소켓생성

ò

구조체에 접속할 서버주소 설정

ò

connect() 연결요청

참고4) 주고 받는 ip / port
위 두함수(client/server)를 통하여 통하여 주고 받는 ip,port를 printf 를 server프로그램에 추가하여 출력하여 보았습니다

결과>>



참고5) 전체 흐름


Posted by mantwo
주소는 크게 3가지방식이 있습니다
1) Domain name    = www.naver.com
2) 32bit ip address  =  0x1000 07f
3) Dotted.decimal   =127.1.1.1




1)aton

소스보기


2)ntoa

소스보기



3)get_host_byaddr

소스보기


4)get_hostent

소스보기

Posted by mantwo

intel cpu little endian를 사용합니다

    Num = 0x12345678 라고 입력했더라도

    메모리에는 78 56 34 12로 저장 되어 있습니다

 

지만 네크워크는 big endian을 사용합니다

참고))motorola cpu계열은 big endian을 사용합니다 바로 넘기면 됩니다!!


 순서대로 읽어드립니다 그래서 pc port ip를 받게되면

Num = 0x78563412 로 나타내게 되어 뒤집어지게 됩니다


그래서 error 가 발생하게 됩니다


struck sockaddr_in
에서

short + 2byte port 9190 경우

1)pc에서 네트워크로 전송시에는 : htons(host to network short)

2)네트워크에서 pc 전송시에는 : ntohs(network to host short)


long + 4byte ip
주소

1)pc에서 네트워크로 전송시에는 : htonl(host to network long)

2)네트워크에서 pc 전송시에는 : ntohl(network to host long)

 

요약하자면 이렇습니다


/* host에서 network로 저장되는것을 확인 하는 프로그램*/

 

#include <stdio.h>

int main ()
{
             short host_port_order = 0x1234;
             short net_port_order;
    
             long host_add_order = 0x12345678;
             long net_add_order;

             net_port_order = htons(host_port_order);
             net_add_order = htonl(host_add_order);

             printf("Host ordered port : %x \n", host_port_order);
             printf(" Nerwork ordered port : %x \n\n", net_port_order);

             printf("Host ordered address : %x \n", host_add_order);
             printf(" Nerwork ordered address : %x \n\n", net_add_order);

             return 0;
}

 

결과>>

호스트에 저장된 숫자(포트, ip)가 네트워크상에서 읽혀지도록 htons, htols를 사용하여

변환된 결과를 확인한 결과 1234 3412 로 확인 할수있습니다

 

Posted by mantwo

TCP/IP

1. 프로토콜(Protocol) - 종단 시스템간 어떻게 데이터 교환을 할 것인지 정한 통신 규약

2. TCP/IP - 호스트들이 상호 통신하기 위한 표준화된 프로토콜

3. TCP/IP 프로토콜 계층 구조


소켓(Socket)
1. 소켓이란 떨어져 있는 두 호스트를 연결해주는 도구를 말합니다

2. 운영체제가 만들어 주는 S/W적인 장치

3. 트랜스포트 계층(TCP,UDP)을 이용하는 API

4. 소켓을 생성한다는 것은 시스템 내부적으로 통신에 필요한 리소스를 할당하는 것을 의미함 


소켓통신 흐름의 이해


LInux의 특징

1) Linux에서는 콘솔, 소켓, 파일 등을 파일로 간주합니다
  1. 모두 파일 디스크립터가 할당됩니다
  2. 파일 입출ㄹ력 함수를 소켓에서도 사용가능합니다
    -read(), write(). close()

2)파일 디스크립터(File Descriptor)
  1. 시스템으로 부터 할당 받은 파일이나 소켓을 대표하는 정수를 말합니다
  2. 파일 디스크립터 0,1,2는 이미 표준 입출력에 할당되어 있습니다
  3. 윈도우즈 기반에서의 handle과 유사합니다

Linux의 파일입출력 함수

1)File 열기 / 닫기


2)데이터 쓰기 / 읽기


Server 소켓 구현

1)소켓 생성



2)주소 할당


3)연결 대기


4)연결 요청 수락


5)소켓 닫기


Client 소켓 구현

1)소켓 생성


2)서버로의 연결 요청



네트워크 프로그래밍 흐름


응용!))
server프로그램이 client프로그램으로 "hello world!"전송

    1. 리눅스에서 server.c client.c 작성
    2. server프로그램을 실행시켜 놓은 상태에서 client 프로그램을 실행시킴

Sever.c

소스보기


Client.c

소스보기


결과>>
컴파일후 server 실행



다른 창에서 client실행


Hello world!가 전송된것을 확인 할 수 있다!

Posted by mantwo