2010년/4월

4월 12일 network(c/s send recv 스레드 분리) ATmega(적외선 감지증가)

뽀얀햄스터 2010. 4. 12. 10:08


네트워크

저번주 금요일에  했던  서버하나에 클라이언트 2개 접속을 배웠다.

하지만  서버에서 send할경우  클라이언트에 한번식  메세지가 전송되거나  하나만 전송되는과정이었

다. 오늘은  서버에서  메세지를 보낼경우  클라이언트가 둘다 전송받는 프로그램이다  .

일단 형태는 다음과  같다.



일단  클라이언트 소스이다.
#include "stdafx.h"
#include <winsock2.h>
#include <windows.h>
#include <process.h>
#include <stdlib.h>
#include <iostream>

#define BUFSIZE 512                  //  BUFSIZE라는 512크기만큼  선언

unsigned int WINAPI ClientProc(LPVOID lpParam);     //컴파일에게 이런  함수가 있다고  알려준다. 주내용:sever로의 접속 &send에 관한 일을 처리한다.
unsigned int WINAPI ClientProc01(LPVOID lpParam);   //컴파일 함수선언  주내용 : recv에  관한 일을  처리한다. 
char buf[BUFSIZE+1];                                //사용할  버퍼의 buf[]배열을 전역변수로 선언
int main(int argc, char* argv[])
{  
  DWORD dwID;                    //thread  ID
  HANDLE h = (HANDLE)_beginthreadex(NULL, 0, ClientProc, NULL, 0, (unsigned *)&dwID);   //sever로의 접속 &send에 관한 일을 처리하는 thread생성
                                            //ClientProc 주소 thread ID의 주소(unsigned *)&dwID                                      
  WaitForSingleObject(h,INFINITE);        //스레드 종료를 기다림    
  printf("Main Thread 종료\n");          //종료메세지 출력
  CloseHandle(h);                  //핸들을 반환  
  return   0;                    //프로그램종료  
}
unsigned int WINAPI ClientProc(LPVOID lpParam)    //thread 시작점

  WSADATA wsa;                  //윈속  DLL초기화를 위한 변수
  int retval;                    //함수의 리턴값을 저장할  변수
  
  if(WSAStartup(MAKEWORD(2,2),&wsa) != 0)         //윈속  초기화 버전  2.2(xp,98,2000등등 xp의 버전은 2,2이다 그 dll를 사용하겠다.
      return -1;                //초기화 실패하면  프로그램종료
  
  SOCKET sock = socket(AF_INET,SOCK_STREAM,0);  //데이터  통신을 위한 소켓생성 % 소켓의 프로토콜 , 연결(동기)비연결(비동기)설정
  
  if(sock == INVALID_SOCKET)            //소켓 초기화에  실패했다면
    printf("소켓 초기화 실패\n");        //에러 출력
                          //serversock setting
  SOCKADDR_IN serveraddr;              //서버의  주소를 담을 변수선언  
  serveraddr.sin_family =AF_INET;          //프로토콜 설정
  serveraddr.sin_port=htons(9000);        //서버의 포토 설정
  serveraddr.sin_addr.s_addr=inet_addr("127.0.0.1");  //접속할 서버의 ip주소  설정(자기자신)
  
  retval=connect(sock,(SOCKADDR*)&serveraddr,sizeof(serveraddr));  //connect함수를 통한 severaddr 주소로  연결 시도
  if(retval==SOCKET_ERROR)            //연결에 실패  했다면
  {
    printf("소켓 연결 실패\n");          //에러출력
    return 0;                  //프로그램종료
  }
            // 데이타 통신 시작
  int len;                    //데이터길이를저장한변수선언      
  DWORD dwID;                    //recvthread의 ID를 저장할 변수 선언
  HANDLE h = (HANDLE)_beginthreadex(NULL, 0,ClientProc01,(LPVOID)sock, 0, (unsigned *)&dwID); //thread생성 ClientProc01주소에 thread ID주소는 dwID
                                                //넘겨줄값 소켓sock값 지정
  while(1)                    //무한 반복문시작
  {
  
    if(fgets(buf,BUFSIZE+1,stdin)==NULL)    //사용자의 입력을 받음
      break;                  //입력받기 실패하면 빠져나감
    
    len=strlen(buf);              //입력 받은  문자열의  길이를 저장
    if(len-1==0)                //저자받은 문자열이 없다면
    { 
      printf("통신을 종료합니다.\n");      //통신종료메세지 출력
      break;                  //while(1) 빠져나감
    }  
    else                    //입력받은 테이터의  마지막에 \0값을 넣음
      buf[len]='\0';              //출력시 에러방지~
    
    //버퍼에 있는 데이타를 전송
    //전송된 데이타의  숫자를 retvla에  저장
    retval= send(sock,buf,strlen(buf),0);
    if(retval==SOCKET_ERROR)          //전송에 실패 했다면
    {
      printf("데이타 전송 에러.\n");      //에러 출력
      break;                  //반복문 빠져나감
    }
    
    printf("[TCP 클라이언트] %d 바이트를 전송 하였습니다.\n",retval); //전소된 바이트 출력
  }    
  //close socket
  closesocket(sock);
  //윈속 종료
  WSACleanup();  
  return 0;
}//recv를 관리하는 thread
unsigned int WINAPI ClientProc01(LPVOID lpParam)
{
  SOCKET client_sock = (SOCKET)lpParam;      //LPVOID lpParam받은 포인터를 
                          //소켓구조체로 변환 
  int retval;                    //함수의 return값을 저장할  변수
  while(1)                    //반복문 실행
  {  
    retval=recv(client_sock,buf,BUFSIZE,0);    //데이타 수신을  대기
    if(retval==SOCKET_ERROR)          //데이타 수신후  결과가 데이타  수신 에러 이면
    { 
      printf("데이타 수신 에러\n");      //에러메세지 출력
      break;                  //반복문을 빠져나옴
    }    
    buf[retval]='\0';              //저장된 buf의 마지막값에  \0을 넘음으로써  출력시 에러방지
    printf("[TCP 클라이언트] %d 바이트를 전송받았습니다.\n",retval); //수신된  바이트의  크기 출력
    printf("[Recv Data] : %s\n",buf);      //수신된 테이터 출력
  }
    return 0;
}

 일단 자세한내용은  주석으로 보면 알수있고 무엇보다  기본적으로   Client에서는 변경사항은 없다.

다음은 sever  부분이다

#include "stdafx.h"
#include <winsock2.h> //windows.h보다 먼저 선언해야함
#include <windows.h>
#include <process.h>
#include <stdlib.h>
#include <iostream>

#define BUFSIZE 512

SOCKET client_sock[2]; //  우리가 나눌 소켓을  전역변수로 선언
int client_num=0;    // 접속할 client 갯수의  초기화(전역변수)

unsigned int WINAPI ServerProc(LPVOID lpParam);  

unsigned int WINAPI ClientContorl01(LPVOID lpParam); //소켓 0번과 통신할  함수 선언
unsigned int WINAPI ClientContorl02(LPVOID lpParam); //소켓 1번과 통신할 함수 선언 
unsigned int WINAPI ClientSendPorc(LPVOID lpParam); // Send를 함수 
int main(int argc, char* argv[])
{
    DWORD dwID;
    
    HANDLE h = (HANDLE)_beginthreadex(NULL, 0, ServerProc, NULL, 0, (unsigned *)&dwID); //스레드 생성
    
    WaitForSingleObject(h,INFINITE);  //스레드 종료를 기다림 
    
    printf("Main Thread 종료\n");
    
    CloseHandle(h);           //핸들을 반환
    
    return 0;
}
unsigned int WINAPI ClientSendPorc(LPVOID lpParam) // client send를 처리할 함수  
{
  char buf[BUFSIZE+1];              //사용할 buf  선언
  int len;                    //데이터  길이를 저장할 변수
  int retval;                    //처음 client  변수 
  int retval2;                  //두번째 들어갈 client 변수 
   while(1)
    {
        ZeroMemory(buf,sizeof(buf));        //buf사이즈만큼 0을 채워  초기화
        printf("\n send data:");
        
        if(fgets(buf,BUFSIZE+1,stdin)==NULL)    //사용자의 입력을 받음~
            break;
        
        len=strlen(buf);              //저장할  문자가없다면 
        if(len-1==0)                //통신종료 
        { 
            printf("통신을 종료합니다.\n");
            break;
        }
        else
            buf[len]='\0';              //출력시  에러방지로 \0을  넣음
        if(client_num==1)              //클라이언트 접속이 한명일시
    {  
      retval= send(client_sock[0],buf,strlen(buf),0);    
      printf("[TCP 클라이언트] %d 바이트를 전송 하였습니다.\n",retval);
      if(retval==SOCKET_ERROR)
      {
        printf("데이타 전송 에러.\n");
        break;
      }
    }
    if(client_num==2)              //클라이언트 접속이  2명일때  아래 전송
    {
      retval= send(client_sock[0],buf,strlen(buf),0);
      retval2= send(client_sock[1],buf,strlen(buf),0);
      printf("[TCP 클라이언트] %d 바이트를 전송 하였습니다.\n",retval);
      printf("[TCP 클라이언트] %d 바이트를 전송 하였습니다.\n",retval2);
      if(retval==SOCKET_ERROR)
      {
        printf("데이타 전송 에러.\n");
        break;
      }
       if(retval2==SOCKET_ERROR)
       {
            printf("데이타 전송 에러.\n");
        break;
       }
        }
  
  
   
       
        
  
    }
  return 0;
}
unsigned int WINAPI ClientContorl02(LPVOID lpParam)//클라이언트 접속시 데이타 처리부분
{   
    SOCKET client_sock = (SOCKET)lpParam;
    char buf[BUFSIZE+1];
    SOCKADDR_IN clientaddr;
    int addrlen;
    int retval;
    
    // client 정보 얻기
    addrlen = sizeof(clientaddr);
    // client소켓을 통해서 주소 정보를 얻어온다.
    getpeername(client_sock,(SOCKADDR *)&clientaddr,&addrlen);
    
    while(1)
    {
        //데이타 받기
        retval = recv(client_sock, buf, BUFSIZE, 0 );
        if(retval == SOCKET_ERROR)
        {
            printf("데이타 받기 실패!");
            break;
        }
        else if(retval==0)
            break;
        
        //데이터 출력
        buf[retval]='\0';
        printf("[TCP/%s:%d] %s\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port),buf);
       
    }
    
    closesocket(client_sock);
    printf("ClientContorl 종료 [TCP서버]:IP 주소:%s, 포트번호=%d\n"\
        ,inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
    
    return 0;
}

unsigned int WINAPI ClientContorl01(LPVOID lpParam)//클라이언트 접속시 데이타 처리부분
{   
    SOCKET client_sock = (SOCKET)lpParam;
    char buf[BUFSIZE+1];
    SOCKADDR_IN clientaddr;
    int addrlen;
    int retval;
    
    // client 정보 얻기
    addrlen = sizeof(clientaddr);
    // client소켓을 통해서 주소 정보를 얻어온다.
    getpeername(client_sock,(SOCKADDR *)&clientaddr,&addrlen);
    
    while(1)
    {
        //데이타 받기
        retval = recv(client_sock, buf, BUFSIZE, 0 );
        if(retval == SOCKET_ERROR)
        {
            printf("데이타 받기 실패!");
            break;
        }
        else if(retval==0)
            break;
        
        //데이터 출력
        buf[retval]='\0';
        printf("[TCP/%s:%d] %s\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port),buf);
        
        //데이터 보내기
        retval = send(client_sock, buf, retval, 0);
        if(retval==SOCKET_ERROR)
        {
        printf("recv error!\n");
        break;
        }
              
    }
    
    closesocket(client_sock);
    printf("ClientContorl 종료 [TCP서버]:IP 주소:%s, 포트번호=%d\n"\
        ,inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
    
    return 0;
}


unsigned int WINAPI ServerProc(LPVOID lpParam)//클라이언트 접속시 데이타 처리부분
{   
    
    WSADATA wsa;
    int retval;
    //윈속 초기화
    if(WSAStartup(MAKEWORD(2,2),&wsa) !=0)
        return -1;
    
    SOCKET listen_sock = socket(AF_INET,SOCK_STREAM,0);
    
    if(listen_sock == INVALID_SOCKET) 
        printf("소켓 초기화 실패\n");
    
    
    SOCKADDR_IN serveraddr;
    
    ZeroMemory(&serveraddr,sizeof(serveraddr));
    serveraddr.sin_family= AF_INET;
    serveraddr.sin_port=htons(9000);
    serveraddr.sin_addr.s_addr=htonl(INADDR_ANY);
    
    //bind 서버의 지역 IP주소와 지역 포트번호를 결정
    //(클라이언트의 접속을 수용할 소켓,이변수늬 주소와 지역포트 번호로 초기화 시킴,소켓주소 구조체변수의 길이)
    retval=bind(listen_sock,(SOCKADDR*)&serveraddr,sizeof(serveraddr));
    if(retval==SOCKET_ERROR)
        printf("bind error\n");
    
    //listen
    //client의 접속을 받아들일수 있는 상태로 포트 상태를 변경한다.
    retval=listen(listen_sock,SOMAXCONN);
    if(retval==SOCKET_ERROR)
        printf("listen error\n");
    
    
    
    
    SOCKADDR_IN clientaddr;
    int addrlen;
    HANDLE hThread01,hThread02,hThread03;
    DWORD THreadID;
    
    //accept()
    addrlen = sizeof(clientaddr);
    //클라이언트에서 접근을 하면 연결을 허락해준다.
    //(소켓 서버, 클라이언트의 주소(sockaddr 타입), 클라이언트 주소의사이즈)
    
    while(client_num<2)
    { 
        printf("client 접속대기\n");
        
        client_sock[client_num] = accept(listen_sock,(SOCKADDR *)&clientaddr,&addrlen);
        if(client_sock[client_num] ==INVALID_SOCKET)
        {
            printf("accept error\n");
        }
        Sleep(1);
        
        printf("[TCP 서버]클라이언트 접속: IP 주소=%s, 포트번호 %d\n",\
            inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
        
        
        switch(client_num)
        {
        case 0:
       hThread03 = (HANDLE)_beginthreadex(NULL, 0, ClientSendPorc,(LPVOID)NULL, 0, (unsigned *)&THreadID); //send()관련 스레드  생성
  
          hThread01 = (HANDLE)_beginthreadex(NULL, 0, ClientContorl01,(LPVOID)client_sock[client_num], 0, (unsigned *)&THreadID); //클라이언트 스레드 생성
           if(hThread01==NULL)
                printf("Client Thread Error\n");           
            break;
        case 1:
            hThread02 = (HANDLE)_beginthreadex(NULL, 0, ClientContorl02,(LPVOID)client_sock[client_num], 0, (unsigned *)&THreadID); //클라이언트 스레드 생성
            if(hThread02==NULL)
                printf("Client Thread Error\n");
           break;
        default:
                printf("잘못된 대기입니다.\n");
                return 0;
        }
        
        client_num++;
    
    }
    
    
    WaitForSingleObject(hThread01,INFINITE);  //스레드 종료를 기다림 
    WaitForSingleObject(hThread02,INFINITE); 
  WaitForSingleObject(hThread03,INFINITE);//스레드 종료를 기다림 
    
    printf("server thread 종료\n");
    CloseHandle(hThread01);
    CloseHandle(hThread02);
  CloseHandle(hThread03);
    closesocket(listen_sock);
    WSACleanup();          //윈속 종료
    return 0;
}

 일단 가장 핵심 두부분을 보자
 if(client_num==1)              //클라이언트 접속이 한명일시
    {  
      retval= send(client_sock[0],buf,strlen(buf),0);    
      printf("[TCP 클라이언트] %d 바이트를 전송 하였습니다.\n",retval);
      if(retval==SOCKET_ERROR)
      {
        printf("데이타 전송 에러.\n");
        break;
      }
    }
    if(client_num==2)              //클라이언트 접속이  2명일때  아래 전송
    {
      retval= send(client_sock[0],buf,strlen(buf),0);
      retval2= send(client_sock[1],buf,strlen(buf),0);
      printf("[TCP 클라이언트] %d 바이트를 전송 하였습니다.\n",retval);
      printf("[TCP 클라이언트] %d 바이트를 전송 하였습니다.\n",retval2);
      if(retval==SOCKET_ERROR)
      {
        printf("데이타 전송 에러.\n");
        break;
      }
       if(retval2==SOCKET_ERROR)
       {
            printf("데이타 전송 에러.\n");
        break;
       }
        }  
일단 기본적으로 2명만 접속이 되기때문에  retval2 변수를 선언하고 기본본적으로  clinet_sock[2]이  전역변수이다  때문에  여기서도 사용이 가능하다 그래서  1명이 들어올경우는 하나만 2명이 들어오면  둘다 사용할수있게 했다.

hThread03 = (HANDLE)_beginthreadex(NULL, 0, ClientSendPorc,(LPVOID)NULL, 0, (unsigned *)&THreadID); 

그리고 이 스레드 생성을  switch문 안에서 0이 들어가자  마자  생성되게 했다. 


-ATMEGA-
 

4. 적외선 센서에 감지 신호를 받을 때마다, FND의 값을 0에서부터 1씩 증가 시키기
#include<avr/io.h>
void
 delay(volatile double inum);
int  main()
{
  DDRE=0xFF;
  PORTE=0xFF;
  DDRD=0x00;
  volatile unsigned char i=0;
  volatile unsigned char s=0;
  volatile unsigned int icnt=0;
  
  
  
  
  while(1)
  {
    asm("NOP");
    i=PIND;
    s=i>>7;
    
    if(s==0)
    {
      PORTE=icnt;
      icnt=icnt+0x01;
      if((icnt&0x0A)==0x0A)
      {
        icnt=icnt+6;
      }
      delay(1);
        
    }    
    if(icnt==0x99)
    {
    
      icnt=0x00;
    }
    
    
  }
  return  0;
}

void delay(volatile double inum)
{
  for(inum=0;15000>inum;++inum)
  {
    ;
      
  }
}

 
FND 값을 1씩 증가시키다가, 적외선 센서 감지 신호를 받으면 일시정지/재개 시키기


#include<avr/io.h>
void
 delay(volatile double inum);
int  main()
{
  DDRE=0xFF;
  PORTE=0xFF;
  DDRD=0x00;
  volatile unsigned char i;
  volatile unsigned char s;
  volatile unsigned char b=1;
  volatile unsigned int icnt=0;
  
  
  
  
  while(1)
  {  
    while(1)
      {
      asm("NOP");
      i=PIND;
      s=i>>7;
      if(s==0)
      {
        b=-b;
        delay(1);  
      }    
      if(b==1)
      {
        PORTE=icnt;
        icnt=icnt+0x01;
        if((icnt&0x0A)==0x0A)
        {
          icnt=icnt+6;
        }
        delay(1);
        if(icnt==0x99)
        {
    
        icnt=0x00;
        }  
        
      }
      
    
    
    
  }
  
    
    
    
  }
  return  0;
}

void delay(volatile double inum)
{
  for(inum=0;15000>inum;++inum)
  {
    ;
      
  }
}

1. 변수 N1, N2에 각각 정수를 입력받아 N1과 N2에 들어있는 정수를 교환하시오.
printf("N1 = %d, N2 = %d", N2, N1); 사용은 불가!!
출력)  N1 입력 : 1
  N2 입력 : 5
  Exchange 결과 : N1 = 5, N2 = 1
#include<stdio.h>
int main()
{
  int N1;
  int N2;
  int swap;
  printf("N1 입력 :\n");
  scanf("%d",&N1);
  printf("\nN2 입력 :\n ");
  scanf("%d",&N2);
  
  swap=N1;
  N1=N2;
  N2=swap;

  printf("N1값=[%d]\tN2값=[%d]\n",N1,N2);
  return 0 ;
}

2. 1바이트 범위의 정수를 입력 받은 다음, 각각의 비트가 켜져 있으면 1, 꺼져 있으면 0을 출력하세요.
출력)  정수 입력(0~255) : 127
  비트   스위치
  ------------------
  0   :  1
  1   :  1
  2   :  1
  3   :  1
  4   :  1
  5   :  1
  6   :  1
  7   :  0
  ------------------
#include<stdio.h>
int  main()
{
  int inum;
  int icnt;
  int a=128;
  int jnum;
  int result[9];
  printf("정수를 입력하세요(0~255사이로)\n");
  scanf("%d",&inum);
  printf("비트   스위치 \n");
  for(icnt=8;icnt>0;--icnt)
  {
    jnum=inum/a;
    inum=inum%a;
    a=a/2;
    result[icnt]=jnum;
  }
  for(icnt=1;9>icnt;++icnt)
  {
    printf("%d   :  %d\n",icnt-1,result[icnt]);
  }
  return 0;
}
3. 10진수 0부터 16까지의 정수를 8진수로 출력합니다. 출력에는 10진수와 8진수의 대응관계를 반드시 포함시킵니다. 10진수 8은 8진수로 10입니다. printf함수의 %o플래그를 사용할 수 없습니다. 
출력)  10진수  8진수
  -----------------
  0  0
  1  1
  2  2
  3  3
  4  4
  5  5
  6  6
  7  7
  8  10
  9  11
  10  12
  11  13
  12  14
  13  15
  14  16
  15  17
  16  20
#include<stdio.h>
int main()
{
   int inum=0;
    int jnum=0;
  printf("10진수\t8진수\n");
   for(inum;inum<21;++inum,++jnum)
   {

    if(inum==8)
    {
      inum=10;

    }
    if(inum==18)
    {
      inum=20;
    }
    printf("%d\t%d\n",jnum,inum);

   }

  return 0;
}

4. 키보드로부터 최대 세 자리의 정수를 입력 받습니다. 자릿수들의 합계는 얼마입니까?
출력)  입력(3자리) : 123
  자릿수 합계 : 6
#include<stdio.h>
int main()
{
  int  inum;
  int icnt;
  int count=100;
  int sum=0;
  int  result=0;

  printf("정수를 입력(3자리)\n");
  scanf("%d",&inum);
  for(icnt=0;icnt<3;++icnt)
  {
    sum=inum/count;
    result=result+sum;
    inum=inum%count;
    count=count/10;
  }

  printf("%d\n",result);
  return 0;
}
5. 1바이트는 8개의 비트로 이루어집니다. 255는 8개 비트 전체가 1인 경우이고, 1은 최하위 1비트만 1인 경우입니다. 문자 ch의 켜진 비트 개수는 몇 개입니까? 켜진 비트는 1로 설정된 비트의 다른 표현입니다. 
대문자 'A'의 값은 65이고 6번째와 1번째 비트가 켜져 있습니다.
출력)  문자 입력 : A
  켜진 비트의 개수 : 2
  값 : 65
#include<stdio.h>
int main()
{
  char cnum;
  int inum;
  int icnt;
  int count=0;
  int fnum;
  printf("문자입력 :\n");
  scanf("%c",&cnum);
  inum=(int)cnum;
  fnum=inum;
  
  for(icnt=0;icnt<8 ;++icnt)
  {
    if(1==(inum&1))
    {
      count++;
    }
    inum=inum>>1;
  }
  printf("켜진비트의 수 : %d\n",count);
  printf("값은  : %d\n",fnum);

  return 0;
}

[도전] 정수 N이 소수입니까? 
출력)  정수 입력 : 97
  결과 : 소수

  정수 입력: 91
  결과 : 합성수[7]
#include<stdio.h>
int main()
{
  int  inum;
  int icnt;
  int count=0;
  int  sum[100];
  int i=0;
  printf("정수를 입력하세요\n");
  scanf("%d",&inum);

  for(icnt=1;icnt<inum;icnt++)
  {
    if(0==inum%icnt)
    {
      count++;
      sum[count]=icnt;      
    }
    

  }
  if(inum==1)
  {
    printf("1은  소수도  합성수도 압니다 \n");
  }
  if(1==count)
  {
    printf("결과 소수\n");
    
  }
  else if(1<count)
  {
    printf("결과  합성수[%d]\n",sum[2]);
  }


  return  0;
}