4월 12일 network(c/s send recv 스레드 분리) ATmega(적외선 감지증가)
네트워크
저번주 금요일에 했던 서버하나에 클라이언트 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-
#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)
{
;
}
}
#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;
}