4월19일 network(nagle알골/넌블로킹client)/Atmaga(C코딩,컴직렬통신)
-네트워크-
동기와 비동기의 차이점
간단하게 동기는 신뢰성이 있고
비동기는 유연성이 있다.
하지만 비동기 데이터를 전송할때 확실하게 상대방에서 보낼때는 정확성이 떨어진다.
또 동기 같은경우는 데이터를 전송할때 만약 send부분이 많다면 보낼때가지 기다려야한다.
비동기같은경우 채팅을 예를 든다면 host에서 볼경우 누가 send했는지 모른다. 그래서 이것이 뒤죽박죽이 된다.
동기에서는 데이터를 보내고 받는곳에서 데이터를 받았다고 ack를 날려준다.
-nagle알고리즘-
Nagle 알고리즘?
1. 네트워크상의 패킷 수를 줄이기 위해 제안된 알고리즘
2. ACK 를 수신해야만 다음 전송을 진행하는 알고리즘
위 그림만 봐도...
Nagle 알고리즘 ON 의 경우에는 패킷수가 훨씬 작은 것을 알 수 있습니다.
N 을 전송하고 ACK 메세지를 받은 다음에 다음 메세지를 전송합니다.
#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;
//갯수
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;
}
// 링커->입력->추가종속성에 ws2_32.lib를 추가 해주어야 한다.
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 타입), 클라이언트 주소의사이즈)
//client_sock==INVALID_SOCKET
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
{
if(sock_count>=0)
{
hThread = (HANDLE)_beginthreadex(NULL, 0, ClientContorl,(LPVOID)client_sock, 0, (unsigned *)&THreadID); //스레드 생성
}
gsock[sock_count]=client_sock;
printf("[TCP 서버]클라이언트 접속: IP 주소=%s, 포트번호 %d\n",\
inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
printf("client 접속자 %d\n",sock_count+1);
sock_count++;
}
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)//클라이언트 접속시 데이타 처리부분
{
// SOCKET client_sock = (SOCKET)lpParam;
char buf[BUFSIZE+1];
SOCKADDR_IN clientaddr;
int addrlen;
int retval;
// client 정보 얻기
// addrlen = sizeof(clientaddr);
// getpeername(client_sock,(SOCKADDR *)&clientaddr,&addrlen);
while(1)
{
//데이타 받기
// printf(" 수신 대기\n");
Sleep(500);
int a=0;
for(int i=0;i<sock_count;++i)
{
retval = recv(gsock[i], buf, BUFSIZE, 0 );
if(retval == SOCKET_ERROR)
{
if(WSAGetLastError()!=WSAEWOULDBLOCK)
{
// printf("데이타 받기 실패!");
// break;
a++;
}
}
else if(retval==0)
{
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--;
if(sock_count==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;
}
}
}
if(a==3)
{
break;
}
}
printf("sever 종료\n");
return 0;
}
이것은 3명이 들어와서 종료해야 다종료가 되는.. 아직 미완성임
-ATMEGA-
1. 난수를 발생하는 rand 함수를 활용하여 주사위를 10번 던졌을 때 주사위 값을 출력하시오.
(주사위 값 : 1~6)
출력) dice value : 5
dice value : 2
dice value : 1
...
dice value : 1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
int inum;
int icnt;
srand((int)time(NULL));
for(icnt=0;icnt<10;++icnt)
{
inum=(rand()%6+1);
printf("dice value : %d\n",inum);
}
return 0;
}
2. 출현 빈도 그래프
" 0에서부터 9까지의 60개의 수가 배열에 저장되어 있을 때, 배열 원소 60개의 합과 평균을 구하여 출력하고 각 수에 대한 빈도 수를 세어서 다음과 같이 막대 그래프 형식으로 출력하시오
" 프로그램의 주요한 부분에 주석을 명시하시오.
#include<stdio.h>
int main()
{
int inum[60]={5,6,7,2,5,3,9,4,6,4,
4,8,0,6,3,7,0,2,0,8,
7,8,0,5,8,7,3,9,7,8,
3,5,2,9,7,5,3,8,7,2,
7,4,7,2,5,3,8,7,5,6,
4,7,6,1,6,5,7,7,7,6};
int icnt; //배열의 처음부터 끝까지 카운트
int sum=0; //값들의 합
float avarage; //값들의 평균
int count; //0~9까지 갯수 카운트
int ccnt; //0~9까지 개수 증가치
int ppt; //0~9까지 for 비교연산 증가치
for(icnt=0;icnt<60;++icnt) //전체 값의 합계 구함
{
sum=sum+inum[icnt];
}
avarage=(float)sum/60; //전체 값의 평균
printf("Sum of array : %d\n",sum);
printf("Average of Array: %.4f\n",avarage);
printf("no count bar graph\n");
for(ppt=0;ppt<10;++ppt) //0~9까지 비교증가
{
count=0; //개수의 초기화
for(icnt=0;icnt<60;++icnt) //배열0~ 59까지증가
{
if(inum[icnt]==ppt) //0~9까지 비교해서
{
count++; //갯수 구함
}
}
printf("%d %d\t",ppt,count);
for(ccnt=0;ccnt<count;++ccnt) //개수만큼 *출력
{
printf("*");
}
printf("\n");
}
return 0;
}
[도전] 로또 번호 생성 프로그램
" 사용자에게 로또 게임 수를 입력받아 게임의 횟수별로 임의로 6개의 수(1~45)를 자동 생성하는 프로그램을 작성하시오. 단, 생성된 난수는 모두 다른 값이어야 한다.
" 로또 번호는 정수형 배열을 선언하여 설정한다.
" 프로그램의 주요한 부분에 주석을 명시하시오.
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
int inum[6]; //저장될 로또 번호 배열
int i; //로또 횟수
int icnt; //0~5까지의 배열공간
int GameCount; //입력될 로또 횟수
int znum; //0에서 icnt까지 같은값있는지 비교할 수
int bool; //로또번호가 같은값이 들어가면 1 아니면 0
printf("Enter Game count : ");
scanf("%d",&GameCount);
srand((int)time(NULL));
for(i=0;i<GameCount;++i) //로또횟수만큼 for문
{
for(icnt=0;icnt<6;++icnt) //총 6개의 로또번호가 들어감
{
bool=0; //비교되어넣는값 0으로 초기화
inum[icnt]=(rand()%45)+1; //inum[icnt]에 0~45까지 random값입력
for(znum=0;znum<icnt;++znum) //inum[icnt]와 inum[znum] inum[icnt-1]
//까지의 값을 비교
{
if(inum[icnt]==inum[znum]) //비교값이 같으면 icnt에
{ // -1를 넣고 bool값 변경
icnt--;
bool=1;
break;
}
}
if(bool==0) //bool값이 0일때만출력
{
printf("%d\t",inum[icnt]);
}
}
printf("\n");
}
return 0;
}
-단방향 직렬통신-
#include<stdio.h>
#include<windows.h>
int main()
{
char szPort[15]; //포트명을 저장할 변수
wsprintf(szPort,"COM%d",2); //포트 2번으로 통신
HANDLE m_hComn =NULL; //HANDLE생성후 초기값 NULL
m_hComn = CreateFile(szPort,GENERIC_READ|GENERIC_WRITE,0,NULL,
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(m_hComn==INVALID_HANDLE_VALUE) //포트접속실패시 에러
{
printf("(!) Failed to create a Comm Device file \n");
return FALSE;
}
DCB dcb; //DCB 구조체생성
dcb.DCBlength=sizeof(DCB); //포트의 크기 비트레이 바이트크기 등을
GetCommState(m_hComn,&dcb);
dcb.BaudRate=9600;
dcb.ByteSize=8;
dcb.Parity=0;
dcb.StopBits=0;
SetCommState(m_hComn,&dcb);
OVERLAPPED osWrite; //송신용 객체 생성
osWrite.Offset=0;
osWrite.OffsetHigh=0;
osWrite.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
char buf[100]="Hello world \r\n";
while(1)
{
printf("send:%s",buf);
WriteFile(m_hComn,buf,strlen(buf),NULL,&osWrite);
Sleep(1000);
}
CloseHandle(m_hComn);
return 0;
}