본문 바로가기
코스웨어/10년 시스템제어

[시스템제어] 4월 19일 보고서 이민규

by 알 수 없는 사용자 2010. 4. 20.
728x90
반응형

네트워크 non-blocking server 3명 접속 받기

// nonblocking_server.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

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

 

#define BUFSIZE 512

unsigned int WINAPI ServerProc(LPVOID lpParam);
unsigned int WINAPI ClientContorl(LPVOID lpParam);

SOCKET gsock[3];//client sock 정보 저장
int sock_count=0;

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 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");
   
    //---------------넌 블록킹 소켓으로 전환--------
    u_long on =1;
    retval = ioctlsocket(listen_sock,FIONBIO,&on);
    if(retval==SOCKET_ERROR)
    {
        printf("소켓 속성 변경 실패\n");
        return 0;
    }
    //----------------------------------------------
   
    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");
   
   
    SOCKET client_sock;
    SOCKADDR_IN clientaddr;
    int addrlen;
    HANDLE hThread;
    DWORD THreadID;
   
    //accept()
    addrlen = sizeof(clientaddr);
    //클라이언트에서 접근을 하면 연결을 허락해준다.
    //(소켓 서버, 클라이언트의 주소(sockaddr 타입), 클라이언트 주소의사이즈)
   
    printf("client 접속대기\n");
   
    Sleep(1000);
   
    while(sock_count<3)
    {
        //printf("client 접속대기\n");
        client_sock = accept(listen_sock,(SOCKADDR *)&clientaddr,&addrlen);
        if(client_sock ==INVALID_SOCKET)
        { //WSAEWOULDBLOCK이란 읽을려고 하는데 첫번째 데이터가 없을때 발생이 된다.
            //즉 NonBlocking 모드에서는 자주 발생할수 밖에 없는 에러이다.
            if(WSAGetLastError()!=WSAEWOULDBLOCK)
                printf("accept error\n");
        }
        else   
        {  
            gsock[sock_count]=client_sock;
           
            printf("client 접속자 : %d 명\n",sock_count+1);
           
            printf("[TCP 서버]클라이언트 접속: IP 주소=%s, 포트번호 %d\n",\
                inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
           
            sock_count++;
           
            if(sock_count==1){
                hThread = (HANDLE)_beginthreadex(NULL, 0, ClientContorl,(LPVOID)client_sock, 0, (unsigned *)&THreadID); //스레드 생성
            }
     
        }
       
        Sleep(500);
    }
   
    if(hThread==NULL)
        printf("Client Thread Error\n");
   
    WaitForSingleObject(hThread,INFINITE);  //스레드 종료를 기다림
   
    printf("server thread 종료\n");
    CloseHandle(hThread);
    closesocket(listen_sock);
    WSACleanup();          //윈속 종료
    return 0;
}

 

unsigned int WINAPI ClientContorl(LPVOID lpParam)//클라이언트 접속시 데이타 처리부분
{
    char buf[BUFSIZE+1];
    SOCKADDR_IN clientaddr;
    int addrlen;
    int retval;
   
    // client 정보 얻기
   
   
    while(1)
    {
        if(sock_count==0)
            break;
        //데이타 받기
        printf("데이타 수신 대기\n");
        Sleep(500);
       
        for(int i=sock_count-1; i>=0; i--)
        {
            retval = recv(gsock[i], buf, BUFSIZE, 0 );
           
            if(retval == SOCKET_ERROR)
            {  
                int error;
                error=WSAGetLastError();
               
                if(error==WSAECONNRESET)//소켓종료 메시지
                {
                    for(int num=i; num<sock_count; num++)
                    {  
                       
                        addrlen = sizeof( gsock[num]);
                        getpeername( gsock[num],(SOCKADDR *)&clientaddr,&addrlen);
                        closesocket( gsock[num]);
                        printf("ClientContorl 종료 [TCP서버]:IP 주소:%s, 포트번호=%d\n"\
                            ,inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
                       
                        if(num==2)
                        {
                            break;
                        }
                        gsock[num] = gsock[num+1];
                    }
                   
                    sock_count--;
                    break;
                }
                else if(error!=WSAEWOULDBLOCK)
                {
                    printf("데이타 받기 실패!");
                    break;
                }
               
            }
            else if(retval ==0)
            {
                break;
            }
            else
            {
                //데이터 출력
                buf[retval]='\0';
                printf("[TCP/%s:%d] %s\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port),buf);
               
                //데이터 보내기
                retval = send(gsock[i], buf, retval, 0);
                if(retval==SOCKET_ERROR)
                {
                    printf("recv error!\n");
                    break;
                }
            }
        }
    }
   
    printf("server 종료....\n");
   
    return 0;
}

-AVR 스탑워치-

포즈 기능과 리셋기능(포즈 기능 까지만 완료)

#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>

volatile unsigned int g_elapsed_time;
volatile unsigned char c;
void initLED(void);
void initFND(void);
void setTCCR0(void);
void initTCNT0(void);
void setTIMSK(void);
void FNDLED(void);
void sleep(unsigned int elapsed_time);
SIGNAL(SIG_OUTPUT_COMPARE0);

int main(void)
{
 
     initLED();
   initFND();
   setTCCR0();
   initTCNT0();
   setTIMSK();
  sei();
 
  while(1)
  {
    FNDLED();
  }
 return 1;
}
void FNDLED(void)
{
 volatile unsigned char a;
 volatile unsigned char b;
 volatile unsigned char c;
 for(b=1;;b++)
 {
  
  for(a=0;a<=153;a++)
  {
   c=PINC;
   if(a%16>9)
     {            
    a=a+6;
     }
   if(~c&1<<0==1)
   {
    for(;;)
    {
     sleep(10);
     c=PINC;
     if(~c&1<<0==1)
     {
      
      break;
     }
     
    }
    
   }
   sleep(10);
   PORTE=a;
  } 
  PORTF=~b;
 }

}
void initFND(void)
{
 DDRE=0xff;
 PORTE=0x00;
}

void initLED(void)
{
  DDRF = 0xFF;
  PORTF = 0xFF;
}
void setTCCR0(void)
{
  TCCR0|=4;
  TCCR0|=8;
}
void initTCNT0(void)
{
  OCR0=250;
  TCNT0=0;
}
void setTIMSK(void)
{
  TIMSK=2;
}
void sleep(unsigned int elapsed_time)
{
  g_elapsed_time=0;
  while(g_elapsed_time<elapsed_time)
  {
  }
 
}
SIGNAL(SIG_OUTPUT_COMPARE0)
{
  g_elapsed_time++;
}

-포즈 기능에서 빠른 제어 속도로 인해

if(~c&1<<0==1)
   {
    for(;;)
    {
     sleep(10);
     c=PINC;
     if(~c&1<<0==1)
     {
위 소스 처럼 슬립함수를 이용해서 딜레이를 줘야 하는 문제가 발생

딜레이를 주다 보니 그 함수로 인해 같은 스위치로 제어하는 포즈기능이 제대로 즉각즉각 반응 하지 않는 문제 발생
----> 같은 스위치로 제어하기 보다 멈춤과 재동작을 나눠서 다른 스위치로 제어 하면 문제점이 고쳐짐.

728x90