728x90

TCP 클라이언트

 

 

소켓 인터페이스를 사용할 때 통신의 단계에 따라 서버와 클라이언트의 사용 방법이 각각 다르므로 클라이언트 및 서버의 구분은 매우 중요하다. 일단 클라이언트부터 알아보자. 클라이언트의 임무는 수동적으로 접속을 기다리고 있는 서버에게 통신을 개시하는 것이다. 전형적인 TCP 클라이언트의 통신은 다음의 4가지 단계를 가진다.

1. socket()를 이용하여 TCP 소켓을 생성
2. connect()를 이용하여 서버와의 연결을 설정
3. send(), recv()를 이용하여 통신을 수행
4. close()를 이용하여 연결을 종료

TCPEchoClient4.c는 IPv4 기반의 TCP에코 클라이언트를 구현한 코드이다.

#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"


int main(int argc, char *argv[])
{
  char *servIP = argv[1];    //첫 번째 인자: 서버IP주소(dotted 형식)
  char *echoString = argv[2];  //두 번째 인자: 보내려는 에코 문자열
  int sock;
  struct sockaddr_in servAddr;      //서버주소
  int rtnVal;
  in_port_t servPort;
  size_t echoStringLen;
  ssize_t numBytes;
  unsigned int totalBytesRcvd = 0;
  
  if(argc < 3 || argc > 4)  //명령어 인자의 정확한 개수 확인
  {
    DieWithUserMessage("Parameter(s)","<Server Address><Echo Word>[<Server Port>]");
  }


  //세 번째 인자(선택): 서버포트(숫자형식). 7이 잘 알려진 포트로 생략 시 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, 0sizeof(servAddr));  //0으로 구조체 초기화
  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()""sent unexeected number of bytes");
  }

  //서버로부터 동일한 문자열 수신
  totalBytesRcvd = 0;  //수신한 문자 개수
  fputs("Received: ", stdout);    //돌려받은 에코 문자열 출력을 위한 설정
  while(totalBytesRcvd < echoStringLen)
  {
    char buffer[BUFSIZE];  //입출력 버퍼
    
/*버퍼크기(byte)만큼 서버로부터 수신
     * (널 문자를 위해 1바이트 남겨놓음)*/

    numBytes = recv(sock, buffer, BUFSIZE - 10);
    if(numBytes < 0)
    {
      DieWithSystemMessage("recv() failed");
    }

    else if(numBytes == 0)
    {
      DieWithUserMessage("recv()""connection closed prematurely");
    }

    totalBytesRcvd += numBytes;  //총 받은 크기를 기록
    buffer[numBytes] = '\0';  //널 문자를 추가하여 문자열 완성
    fputs(buffer, stdout);    //에코 버퍼를 출력
  }

  fputc('\n', stdout);  //마지막으로 개행문자 출력

  close(sock);
  exit(0);
}

 

 

Practical.h

#ifndef
 __Practical_h__
#define __Practical_h__

#define BUFSIZE 100

void DieWithUserMessage(const char *msg, const char *detail);

void DieWithSystemMessage(const char *msg);

#endif

 

 

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

 

 

 

IPv4 TCP 서버
서버의 역할은 통신 종단점의 설정과 클라이언트의 접속을 기다리는 것이다. TCP서버는 다음과 같은 4단계의 통신 과정을 일반적으로 가지게 된다.

1. socket()를 통해 TCP 소켓을 생성
2. bind()를 통해 소켓에 포트 번호를 할당
3. listen()을 통해 해당 포트가 연결을 받아들이도록 시스템에 알림
4. 다음과 같은 일을 계속적으로 반복
 - accept()를 통해 각 클라이언트와 통신에 필요한 새로운 소켓을 획득
 - 새롭게 생성된 클라이언트 소켓에 send(), recv()를 호출하여 통신을 수행
 - close()를 통해 클라이언트와 연결을 종료

소켓의 생성, 데이터 송신, 수신, 소켓 종료 등은 클라이언트와 동일하다. 서버가 소켓을 사용하는데 있어서 클라이언트와 다른 점은 주소를 소켓에 바인드(bind)한다는 것이며, 그 소켓을 클라이언트와 연결이 되는 또 다른 소켓을 생성하는 매개체로 이용한다는 것이다. 서버가 클라이언트와 통신하는 과정은 단순하다.
클라이언트로부터 데이터를 받아서 동일한 데이터를 클라이언트에게 다시 돌려보내게 되며, 이 과정은 클라이 언트가 연결을 종료할 때까지 반복한다.

TCPEchoServer4.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[])
{
  in_port_t servPort;
  int servSock;  //서버 소켓 식별자
  struct sockaddr_in servAddr;          //지역 주소
  char clntName[INET_ADDRSTRLEN];  //클라이언트 주소를 담기 위한 문자열
  
  if(argc != 2)  //명령어 인자의 개수 확인
  {
    DieWithUserMessage("Parameter(s)""<Server Port>");
  }

  servPort = atoi(argv[1]);  //첫 번째 인자 : 지역 포트

  //연결 요청을 처리하는 소켓 생성

  if((servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  {
    DieWithSystemMessage("socket() failed");
  }

  //지역 주소 구조체 생성
  memset(&servAddr, 0sizeof(servAddr));      //0으로 구조체 초기화
  servAddr.sin_family = AF_INET;          //IPv4 주소 패밀리
  servAddr.sin_addr.s_addr = htonl(INADDR_ANY);  //호스트의 어떠한 IP로도 연결 요청 수락
  servAddr.sin_port = htons(servPort);      //지역 포트

  //지역 주소에 바인드
  if(bind(servSock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
  {
    DieWithSystemMessage("bind() failed");
  }

  //소켓이 들어오는 요청을 처리할 수 있도록 설정
  if(listen(servSock, MAXPENDING) < 0)
  {
    DieWithSystemMessage("listen() failed");
  }

  for(;;)
  {
    struct sockaddr_in clntAddr;  //클라이언트 주소
    //클라이언트 주소 구조체의 크기설정
    socklen_t clntAddrLen = sizeof(clntAddr);

    //클라이언트의 연결을 기다림
    int clntSock = accept(servSock, (struct sockaddr *) &clntAddr, &clntAddrLen);
    if(clntSock < 0)
    {
      DieWithSystemMessage("accept() failed");
    }

    //clntSock가 클라이언트와 연결됨!
    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);
  }
  //실행되지 않음
  return 0;
}

 

 

HandleTCPClient.c

#include <stdio.h>
#include <stdlib.h>

#define BUFSIZE 100

void HandleTCPClient(int clntSocket)
{
  char buffer[BUFSIZE];  //에코 문자열을 위한 버퍼
  ssize_t numBytesSent;
  ssize_t numBytesRcvd;

  //클라이언트로부터 메시지 수신
  numBytesRcvd = recv(clntSocket, buffer, numBytesRcvd, 0);
  if(numBytesRcvd < 0)
  {
    DieWithSystemMessage("recv() failed");
  }

  //수신한 문자열을 전송하고 여분의 데이터를 스트림이 끝날 때까지 수신
  while(numBytesRcvd > 0)
  {
    //클라이언트로 에코 메시지를 돌려보냄
    numBytesSent = send(clntSocket, buffer, numBytesRcvd, 0);
    if(numBytesSent < 0)
    {
      DieWithSystemMessage("sent() failed");
    }

    else if(numBytesSent != numBytesRcvd)
    {
      DieWithSystemMessage("sent()""sent unexpected number of bytes");
    }

    //받을 수 있는 데이터가 더 남아 있는지 확인
    numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0);
    if(numBytesRcvd < 0)
    {
      DieWithSystemMessage("recv() failed");
    }
  }
  close(clntSocket);  //클라이언트 소켓 종료
}

 

 

실행
먼저 각 함수들 *.o파일을 생성한다.
gcc -c 함수입력한파일.c
그러면 함수입력한파일.o가 생성된다.

그 다음 server와 client실행파일 생성
예) gcc -o TCPEchoServer4 TCPEchoServer4.c HandleTCPClient.o
예) gcc -o TCPEchoClient4 TCPEchoClient4.c DieWithMessage.o
이렇게 실행파일 생성 후

서버 실행
TCPEchoServer4 포트번호

클라이언트 실행
TCPEchoClient4 IP주소 "Hello world" 포트번호

결과

 

 


 

 

728x90

talk_server.c

 
#include<stdio.h>
#include<string.h>

#include<stdlib.h>
#include<sys/types.h>
#include<signal.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<sys/wait.h>

#define MAXLINE 512

void z_handler();// 시그널 처리 함수

char *escapechar = "exit"// 종료 문자열

int main(int argc, char *argv[])
{
  int server_sock;
  int client_sock;
  int clntlen;
  int num;
  char sendline[MAXLINE];
  char recvline[MAXLINE];
  int size;
  pid_t fork_ret;
  struct sockaddr_in client_addr;
  struct sockaddr_in server_addr;
  int state;
  struct sigaction act;
  act.sa_handler = z_handler;

  if(argc!=2)
  {
    printf("Usage : %s PORT \n", argv[0]);
    exit(0);
  }
  // 소켓 생성
  if((server_sock = socket(PF_INET, SOCK_STREAM, 0)) <0)
  {
    printf("Server : can't open stream socket. \n");
    exit(0);
  }
  // 소켓 주소 구조체에 주소 세팅
  bzero((char *)&server_addr, sizeof(server_addr)); // 소켓 주소 구조체 초기화
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  server_addr.sin_port = htons(atoi(argv[1]));

  sigaction(SIGCHLD, &act, 0);

  // 소켓에 서버 주소 연결
  if(bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
  {
    printf("Server : can't bind local address.\n");
    exit(0);
  }
  printf("Server started. \nWaiting for client.. \n");
  listen(server_sock, 1);

  // 클라이언트의 연결요청 수락
  clntlen = sizeof(client_addr);
  if((client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &clntlen)) <0)
  {
    printf("Server : failed in accepting. \n");
    exit(0);
  }
  if((fork_ret = fork()) > 0)
  {
    // 부모 프로세스는 키보드 입력을 클라이언트로 송신
    while(fgets(sendline, MAXLINE, stdin)!=NULL)
    {
      size = strlen(sendline);
      if(write(client_sock, sendline, strlen(sendline)) != size)
      {
        printf("Error in write. \n");        
      }
      if(strstr(sendline, escapechar) != NULL) // 종료 문자열 입력시 처리
      {
        printf("Good bye.\n");
        close(client_sock);
        while(1);    //자식프로세서가 죽을때까지 블로킹 
      }
    }
  }
  else if(fork_ret == 0)
  {
    // 자식 프로세스는 클라이언트로부터 수신된 메시지를 화면에 출력
    while(1)
    {
      if((size = read(client_sock, recvline, MAXLINE)) < 0)
      {
        printf("Error if read. \n");
        close(client_sock);
        exit(0);
      }
      recvline[size] = '\0';
      if(strstr(recvline, escapechar) != NULL) // 종료 문자열 입력시 처리
      {
        write(client_sock, escapechar, strlen(escapechar));
        break;
      }
      printf("%s", recvline); // 화면 출력
    }
  }
  close(server_sock);
  close(client_sock);

  return 0;
}
void z_handler()
{
  int state;
  waitpid(-1&state, WNOHANG);
  exit(0);

  return ;
}

 

-------------------------------------------------------------------------------------------

 

talk_client.c
 
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<signal.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/wait.h>

#define MAXLINE 1024

void z_handler();

char *escapechar = "exit"// 종료 문자열

int main(int argc, char *argv[])
{
  char line[MAXLINE], sendline[MAXLINE], recvline[MAXLINE+1];
  int n, size, comp, addr_size;
  pid_t fork_ret;

  static int s;
  static struct sockaddr_in server_addr;
  struct sigaction act;
  act.sa_handler = z_handler;
  

  if(argc != 3)
  {
    printf("Usage : %s serverIP serverPORT \n", argv[0]);
    exit(0);
  }

  // 소켓 생성
  if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
  {
    printf("Client : can't open stream socket.\n");
    exit(0);
  }
  // 소켓 주소 구조체에 접속할 서버 주소 세팅
  bzero((char *)&server_addr, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = inet_addr(argv[1]);
  server_addr.sin_port = htons(atoi(argv[2]));

  sigaction(SIGCHLD, &act, 0);
  // 서버에 연결 요청
  if(connect(s, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
  {
    printf("Client : can't connect to server.\n");
    exit(0);
  }
  fork_ret = fork();
  if(fork_ret > 0)
  {
    // 부모 프로세스는 키보드 입력을 서버로 송신
    while(fgets(sendline, MAXLINE, stdin) != NULL)
    {
      size = strlen(sendline);
      if(write(s, sendline, strlen(sendline)) != size)
      {
        printf("Error in write. \n");
      }
      if(strstr(sendline, escapechar) != NULL) // 종료 문자열
      {
        printf("Good byte.\n");
        close(s);
        while(1);    //자식프로세서가 죽을때까지 블로킹
      }
    }
  }
  else if(fork_ret == 0)
  {
    // 자식 프로세스는 서버로부터 수신된 메시지를 화면에 출력
    while(1)
    {
      if((size = read(s, recvline, MAXLINE)) < 0)
      {
        printf("Error if read. \n");
        close(s);
        return 0;
      }
      recvline[size] = '\0';
      if(strstr(recvline, escapechar)!=NULL) // 종료 문자열
      {
        write(s, escapechar, strlen(escapechar));
        break;
      }
      printf("%s", recvline); // 화면 출력
    }
  }
  close(s);
  return 0;
}
void z_handler()
{
  int state;
  waitpid(-1&state, WNOHANG);
  exit(0);

  return ;
}
 
728x90

퀄컴의 P2P 기술 Alljoyn (올조인)

기술 & 트렌드 2011/10/06 17:13

휴대폰용 무선모뎀과 모바일 프로세서를 주로 개발하는 Qualcomm이 독자적인 P2P 기술을 가지고 있는 것을 아는 사람은 얼마나 될까? 나 역시 Qualcomm Social Media Day(퀄컴 소셜 미디어 데이)에서 기술에 대한 자세한 소개를 받기 전까지는 Qualcomm 근거리 P2P 통신 기술을 가지고 있는지 몰랐다.


Alljoyn™(
올조인)이라는 기술은 Qualcomm 산하 Qualcomm Inovation Center(QuIC)가 개발하였으며, 오픈소스화 하여 개발자 누구나 무료로 이 기술을 이용할 수 있도록 하고 있다. QuIC는 오픈소스 개발에 촛점을 맞춘 Qualcomm 하부 조직이다.

우선 Alljoyn은 근거리 기반의 기기간 Peer-to-Peer 기술이다. 하드웨어에 의존하는 방식이 아닌 기존의 무선통신 방식, 이를테면 Bluetooth Wi-Fi 등의 물리적인 통신방식 위에 소프트웨어 프레임워크로 만들어진 기술이다.

Alljoyn
Ad hoc(애드혹) 기반 기술이어서 단독으로 기기와 기기 사이의 통신만 제공한다. node link만이 존재하는 것이다. 이런 기기가 상호 연결을 통해 네트워크를 구성할 수 있게 되면서 동시에 여러 기기로 연결이 가능한 구조다.

P2P
를 이용한 기술이지만 중계 서버가 없다는 점도 특징으로 꼽을 수 있다. 어떤 P2P 기술들은 중계서버를 통해 노드(node) 정보를 저장하여 기록 보관하면서 연결 자체만 P2P로 해주는 경우도 많지만, Alljoyn은 오로지 기기사이의 P2P만 제공한다.

Alljoyn
Bluetooth Wi-Fi 부품을 제어 및 작동시킬 수 있는 HLOS(High Level OS)[각주:1]위에 소프트웨어 프레임워크 형태로만 존재한다. 따라서 개발자가 운영체제의 커널이나 부품의 제어에 관한 부분을 신경쓰지 않아도 된다는 점이 장점이라 할 수 있다.

Bluetooth
Wi-Fi 기반 위의 기술이어서 모바일 기기에 적합한 것임을 눈치챌 수 있다. 따라서 모바일 애플리케이션 개발자라면 소스가 공개되어 있는 Alljoyn을 이용하여 애플리케이션을 만들 수 있다. 현재 공개된 API 소스는 C++ Java로 되어 있으며, Android 버전의 SDK가 공개되어 있다.

크로스 플랫폼의 서로 다른 통신 기술을 지원하는 Alljoyn


그렇다면 Alljoyn으로 무엇을 할 수 있을까?

우선 Alljoyn OS에 크게 구애받지 않는 Cross Platform(크로스 플랫폼) 기술이다. Windows 기반의 노트북이나 Linux 기반의 기기, 혹은 Android 기기끼리도 통신이 가능하며, 이들 이기종 OS 사이에서도 동작을 한다.

현재는 Windows 7 XP, Andorid 2.1 이상, Linux를 지원하지만 머지않아 iOS Windows Phone을 지원할 계획을 가지고 있어서 노트북이나 넷북, 타블렛, 스마트폰 등의 웬만한 모바일 기기는 모두 지원할 수 있게 된다.

Alljoyn
을 이용한 서비스는 다양하게 만들어낼 수 있는데, 대표적인 것이 멀티플레이어 게이밍과 소셜 미디어 쉐어링, 멀티유저방식의 애플리케이션 툴로 이용하는 방법들이다.

근거리 통신을 통해 여러 사람이 게임을 하게 만들고 싶다면 Alljoyn을 이용하면 구현할 수 있다. 상호 인증을 통해 접속을 허용하여 P2P로 서로 게임을 즐길 수 있는 것이다. 이런 기술은 이미 Bluetooth를 기반으로 구현되어 있지만, Alljoyn을 이용하면 Wi-Fi 기반에서도 구현이 가능하다.

Alljoyn으로 연결된 스마트폰과 노트북 (출처 : Engadget)


미디어 쉐어링(Media Sharing) 역시 Alljoyn의 기본 활용분야다. 하나의 기기에 저장되어 있는 음악이나 사진, 동영상 등을 Alljoyn으로 연결된 다른 기기에서 재생하거나 옮길 수 있게 된다.

9
26일에 열린 퀄컴 소셜 미디어 데이에서는 3 대의 안드로이드폰에서 음악을 공유하는 방법을 시연했는데, Alljoyn을 지원하는 미디어 플레이어에서 상대방이 가지고 있는 음악을 자신의 기기에서 재생하는 데모를 보여줬다.

연인들이나 친구들끼리 음악이나 사진 등의 공유를 통해 즐거움을 나눌 수 있는 방법을 제공하는 것이다. 자신이 좋아하는 음악을 직접 고르고 이를 연인이나 친구들과 동시에 들을 수 있으며, 반대로 상대방이 고른 음악도 들을 수 있다.

만일 차량용 기기에 Alljoyn을 응용한다면 미리 스마트폰에 설정한 음악 플레이리스트를 이용하여 차량용 카오디오 시스템을 통해 즐길 수도 있게 된다.

Alljoyn
을 이용하면 스마트폰에 있는 동영상 파일을 더 큰 화면을 가진 타블렛 컴퓨터에서 재생할 수도 있다. 이른바 멀티 스크린 경험도 가능하다. 해상도와 통신 속도만 제대로 지원해 준다면 모바일 기기에서 디지털 TV로의 출력도 어렵지 않을 것으로 보인다. 물론 지금 당장 구현되지는 않은 상태다.

Alljoyn을 이용한 사진 공유 (출처 : Endgadget)


그 외에도 가장 일반적으로 기기 사이의 미디어 공유 혹은 전달 기능을 이용할 수도 있다. 스마트폰의 Bump 애플리케이션처럼 주소록이나 사진, 음악 등을 서로 주고받을 수 있다.

더 가능성 있는 분야는 현재 제공되지 않는 비즈니스 도구로서의 활용방안인데, Alljoyn을 채용한 애플리케이션을 통해 근거리 광고, 쿠폰 발행, 이벤트 안내 등의 기능을 활용할 수도 있다.

소비자가 허락만 한다면 매장에서 Wi-Fi를 무료로 제공고 각종 광고나 쿠폰, 이벤트 소개를 할 수도 있을 것이다. 그 외에도 활용 방안은 무궁무진하다. 예를들면, 같은 지역 내에 있는 방문자들 끼리의 네트워크 연결에도 사용할 수 있는데, 서로 모르는 사람끼리도 커뮤니케이션 할 수 있다.

Alljoyn
Apache 2.0 라이선스 하의 오픈소스 프로젝트 라이선스를 받았다. , 상용화에 대한 큰 부담이 없다는 장점이 있는데, 파생 개발된 모든 코드를 공개해야 할 의무가 없다는 큰 장점이 있다. Alljoyn을 이용한 상용 소프트웨어 개발에 있어 상당한 자유를 준다는 점에서 기업들이 반길만한 부분이다.

Alljoyn
MWC 2011에서 처음으로 공개되었고, 지난 6월 첫 Initial 버전인 A 버전을 릴리즈 하였다. 이와 관련된 모든 정보나 소프트웨어 프레임워크 소스는 다음 웹사이트를 참고하면 된다.

Alljoyn
웹사이트 : http://www.alljoyn.org

Alljoyn
Qualcomm 직원이 생각해낸 아이디어를 기반으로 만들어진 기술이라고 한다. 스마트폰에 있는 음악을 자신의 차에서 쉽게 듣기 위한 방법을 고민을 하던 중 떠오른 아이디어를 실제 기술로 구현한 사례라고 한다. 이런 사례만 봐도 기술 혁신은 생활속에 필요에 의해 쉽게 구현되는 것 같다.

*
올해로 두 번째 열리는 Qualcomm 소셜 미디어 데이에 처음 참석했는데, 상당히 유용한 정보들을 알려줬다. 2개의 세션으로 소비자들이 궁금해할 Qualcomm 제품과 기술에 대해 소개했는데, 다음에도 새로운 제품과 기술 동향을 알려줬으면 좋겠다.

  1. HLOS Android Linux, Windows Phone, iOS 같은 Operation System을 말한다. [본문으로]

 

728x90
728x90

 

무선랜 해킹.pdf

 

무선랜 프로토콜 규정 및 해킹 방법 언급(저자: 영동대학교 스마트IT학부: 이호준 hjlee@yd.ac.kr)

 

728x90

 

0623-네트워크_pthread API 및 Fcntl()함수_ver1_0d.docx

 

0623-네트워크_pthread API 및 Fcntl()함수_ver1_0d.pdf

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90

 

0620-네트워크_process_ver1_0a.docx

 0620-네트워크_process_ver1_0a.pdf

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90
728x90
728x90

*[자료 열람시 주의]: Scripter 를 통해 개념만 이해  -> 예제 프로그램은 리눅스 c언어 프로그램 임  

0617-네트워크_문자 전송_ver2_0a.pdf

Makefile 만들기_ver1_0a.pdf