"전체 글"에 해당되는 글 - 365건
Post
아래의 기본 서버 예제는 문제점이 있다.
클라이언트가 많아지면 접속을 제 때 받지 못한다.
또 처리하는 부분(send)도 시간이 많이 걸리면 클라이언트 접속 대기 시간이 생긴다.
둘 다 분리되어있지 않고, 원스레드에서 해결하기 때문이다.
아래는 원스레드 서버의 처리시간이 길어지면 어떤문제점이 있는지 보여주는 예제이다.
상황설정
서버는 원스레드로, 클라이언트 접속 후에 1초걸리는 일을 처리하고 패킷을 전달한다.
클라이언트는 배치 파일을 만들어서 7개가 동시에 Connect를 요청하고 서버의 응답을 기다린다.
bat 파일은 아래와 같이 작성했다.
( ConsoleApplication2.exe 가 클라이언트다.. .;; )
start /d "C:\Users\MyDirectory\Documents\Visual Studio 2017\ConsoleApplication2\Debug\" ConsoleApplication2.exe
start /d "C:\Users\MyDirectory\Documents\Visual Studio 2017\ConsoleApplication2\Debug\" ConsoleApplication2.exe
start /d "C:\Users\MyDirectory\Documents\Visual Studio 2017\ConsoleApplication2\Debug\" ConsoleApplication2.exe
start /d "C:\Users\MyDirectory\Documents\Visual Studio 2017\ConsoleApplication2\Debug\" ConsoleApplication2.exe
start /d "C:\Users\MyDirectory\Documents\Visual Studio 2017\ConsoleApplication2\Debug\" ConsoleApplication2.exe
start /d "C:\Users\MyDirectory\Documents\Visual Studio 2017\ConsoleApplication2\Debug\" ConsoleApplication2.exe
start /d "C:\Users\MyDirectory\Documents\Visual Studio 2017\ConsoleApplication2\Debug\" ConsoleApplication2.exe
<server>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | #include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <winsock2.h> #define BUF_SIZE 30 void ErrorHandling(const char* message); int main() { WSADATA wsaData; SOCKET hServSock, hClntSock; SOCKADDR_IN servAddr, clntAddr; int strLen = 0; int szClntAddr; char message[] = "Hello World!"; if (0 != WSAStartup(MAKEWORD(2, 2), &wsaData)) { ErrorHandling("WSAStartup() error!"); } hServSock = socket(PF_INET, SOCK_STREAM, 0); if (INVALID_SOCKET == hServSock) ErrorHandling("socket() error"); memset(&servAddr, 0, sizeof(servAddr)); servAddr.sin_family = AF_INET; servAddr.sin_addr.s_addr = htonl(INADDR_ANY); servAddr.sin_port = htons(atoi("8888")); if (SOCKET_ERROR == bind(hServSock, (SOCKADDR*)&servAddr, sizeof(servAddr))) { ErrorHandling("bind error \n"); } if(SOCKET_ERROR == listen(hServSock, 5)) { ErrorHandling("listen error \n"); } szClntAddr = sizeof(clntAddr); int i = 0; while(true) { hClntSock = accept(hServSock, (SOCKADDR*)&clntAddr, &szClntAddr); if (-1 == hClntSock) { ErrorHandling("accept() error \n"); } else { printf("Connected clinet : %d \n", i + 1); } ++i; Sleep(1000); send(hClntSock, message, BUF_SIZE, 0); closesocket(hClntSock); } closesocket(hServSock); WSACleanup(); return 0; } void ErrorHandling(const char* message) { fputs(message, stderr); fputc('\n', stderr); exit(1); } | cs |
<Client>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | #include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <ws2tcpip.h> #include <windows.h> #define BUF_SIZE 30 void ErrorHandling(const char* message); int main() { WSADATA wsaData; SOCKET hSocket; SOCKADDR_IN servAddr; char message[30]; int strLen; if (0 != WSAStartup(MAKEWORD(2, 2), &wsaData)) { ErrorHandling("WSAStartup() error!"); } hSocket = socket(PF_INET, SOCK_STREAM, 0); if (INVALID_SOCKET == hSocket) { ErrorHandling("WSAStartup() error!"); } memset(&servAddr, 0, sizeof(servAddr)); servAddr.sin_family = AF_INET; //servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); inet_pton(AF_INET, "127.0.0.1", &servAddr.sin_addr); servAddr.sin_port = htons(atoi("8888")); if(SOCKET_ERROR == connect(hSocket, (SOCKADDR*)&servAddr, sizeof(servAddr))) { printf("error:%d \n", WSAGetLastError()); ErrorHandling("connect() error"); } else { puts("Connected......"); } int beginTime = GetTickCount(); strLen = recv(hSocket, message, BUF_SIZE - 1, 0); int endTime = GetTickCount(); int passTime = endTime - beginTime; message[strLen] = 0; printf("Message from server ms:%d second:%f message:%s \n", passTime, (passTime * 0.001), message); closesocket(hSocket); WSACleanup(); system("pause"); return 0; } void ErrorHandling(const char* message) { fputs(message, stderr); fputc('\n', stderr); exit(1); } | cs |
<결과>
서버는 1초짜리 일을 했지만 접속순서대로 차례대로 일을 처리했기 때문에,
후순위로 Connect한 클라이언트는 5~6초나 지나서 결과를 받았다.
멀티스레드 서버를 사용해야하는 이유다.
'이전게시판 > Server' 카테고리의 다른 글
IOCP 채팅 서버 소스 예제 (0) | 2018.10.04 |
---|---|
C4996 에러 (0) | 2018.09.28 |
LNK2019: __imp__closesocket@4 외부 기호(참조 위치: _main 함수)에서 확인하지 못했습니다. (0) | 2018.09.28 |
구글 프로토콜 버퍼 C++ Window 예제 (Google Protocol buffer) (0) | 2018.07.27 |
C4996 inet_addr Error Solution (0) | 2018.06.30 |
ip주소 추적 (0) | 2018.04.21 |
hosts파일, DNS (0) | 2018.04.21 |
DHCP란? (0) | 2018.04.20 |
Post
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | // ConsoleApplication2.cpp: 콘솔 응용 프로그램의 진입점을 정의합니다. // #include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <winsock2.h> #include <ws2tcpip.h> void ErrorHandling(const char* message); int main() { WSADATA wsaData; SOCKET hSocket; SOCKADDR_IN servAddr; char message[30]; int strLen; if (0 != WSAStartup(MAKEWORD(2, 2), &wsaData)) { ErrorHandling("WSAStartup() error!"); } hSocket = socket(PF_INET, SOCK_STREAM, 0); if (INVALID_SOCKET == hSocket) { ErrorHandling("WSAStartup() error!"); } memset(&servAddr, 0, sizeof(servAddr)); servAddr.sin_family = AF_INET; // servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); inet_pton(AF_INET ,"127.0.0.1", &servAddr.sin_addr); servAddr.sin_port = htons(atoi("8888")); if(SOCKET_ERROR == connect(hSocket, (SOCKADDR*)&servAddr, sizeof(servAddr))) { ErrorHandling("connect() error!"); } strLen = recv(hSocket, message, sizeof(message) - 1, 0); if (-1 == strLen) { ErrorHandling("read() error!"); } printf("Message from server : %s \n", message); closesocket(hSocket); WSACleanup(); return 0; } void ErrorHandling(const char* message) { fputs(message, stderr); fputc('\n', stderr); exit(1); } | cs |
오류 C4996 'inet_addr': Use inet_pton() or InetPton() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API
'이전게시판 > Server' 카테고리의 다른 글
IOCP 채팅 서버 소스 예제 (0) | 2018.10.04 |
---|---|
C4996 에러 (0) | 2018.09.28 |
LNK2019: __imp__closesocket@4 외부 기호(참조 위치: _main 함수)에서 확인하지 못했습니다. (0) | 2018.09.28 |
구글 프로토콜 버퍼 C++ Window 예제 (Google Protocol buffer) (0) | 2018.07.27 |
기본 서버 예제의 문제점 (0) | 2018.07.05 |
ip주소 추적 (0) | 2018.04.21 |
hosts파일, DNS (0) | 2018.04.21 |
DHCP란? (0) | 2018.04.20 |
Post
'etc' 카테고리의 다른 글
클립스튜디오 자기 브러쉬 등록하는 법 (0) | 2024.05.06 |
---|---|
tortoisesvn Path (0) | 2018.05.30 |
No bootable medium found ( VirtualBox Window 10 설치 ) (0) | 2018.05.09 |
[R데이터]네이버 뉴스 크롤링 (0) | 2018.01.09 |
R 기초 - 프로그램 설치 (0) | 2018.01.09 |
래퍼런스, 포인터 차이, 프로시저 사용이유, 외래키? (0) | 2016.04.07 |
Post
'이전게시판 > C, C++' 카테고리의 다른 글
C++ csv 파일 읽기 (0) | 2024.09.25 |
---|---|
c++ 전처리기 region 이란 (0) | 2018.09.30 |
pragma message 출력창에 내용 출력 (0) | 2018.08.29 |
Cygwin 설치 설정 방법 (0) | 2018.07.27 |
flyweight(플라이웨이트) 패턴 (0) | 2018.06.16 |
VisualStudio 줄번호 바로가기 단축키 (0) | 2018.06.05 |
const와 포인터 (0) | 2018.05.30 |
C3083 왼쪽의 기호는 형식이어야 합니다 에러 정방선언... (0) | 2018.05.03 |
Post
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | // ConsoleApplication1.cpp: 콘솔 응용 프로그램의 진입점을 정의합니다. // #include "stdafx.h" #include <vector> using namespace std; class Flyweight { public: struct Stock { int nType; // 0 : 전사 1 : 마법사 int nMaxHP; int nStr; int nDef; }; private: Stock m_stock; public : void SetStock(Stock stock) { m_stock = stock; } Stock& GetStock() { return m_stock; } void Print(int index) { printf("유닛%d Type:%d MaxHP:%d \n", index, m_stock.nType, m_stock.nMaxHP); } }; class Unit { private: Flyweight * m_pFly; public : void SetFly(Flyweight* pFly) { m_pFly = pFly; } Flyweight* GetFly() { return m_pFly; } }; class Container { vector<Flyweight*> m_Container; public: ~Container() { vector<Flyweight*>::iterator it; for (it = m_Container.begin(); it != m_Container.end();) { it = m_Container.erase(it); } } void Insert(int nType) { Flyweight* pNewFly = new Flyweight(); Flyweight::Stock stock; // 타입은 전사, 마법사로 나뉘고 타입별로 스탯은 동일하다 if (0 == nType) { stock.nType = 0; stock.nMaxHP = 100; stock.nStr = 20; stock.nDef = 10; } else { stock.nType = 1; stock.nMaxHP = 50; stock.nStr = 40; stock.nDef = 5; } pNewFly->SetStock(stock); m_Container.push_back(pNewFly); } Flyweight* Search(int nType) { Flyweight* pFly = m_Container.at(nType); return pFly; } }; static Container UnitContainer; // 유닛 생성 class UnitManager { vector<Unit*> m_UnitList; public : ~UnitManager() { vector<Unit*>::iterator it; for (it = m_UnitList.begin(); it != m_UnitList.end();) { it = m_UnitList.erase(it); } } void Create(int nType) { Unit* pUnit = new Unit(); Flyweight* pFly = NULL; pFly = UnitContainer.Search(nType); pUnit->SetFly(pFly); m_UnitList.push_back(pUnit); } Unit* Get(int i) { return m_UnitList.at(i); } }; int main() { // Fly 정보 추가 UnitContainer.Insert(0); UnitContainer.Insert(1); UnitManager unitManager; for (int i = 0; i < 10; ++i) { unitManager.Create(0); } for (int i = 0; i < 10; ++i) { unitManager.Create(1); } unitManager.Get(1)->GetFly()->Print(1); unitManager.Get(3)->GetFly()->Print(3); unitManager.Get(9)->GetFly()->Print(9); unitManager.Get(10)->GetFly()->Print(10); unitManager.Get(15)->GetFly()->Print(15); unitManager.Get(19)->GetFly()->Print(19); //getchar(); } | cs |
출력결과
유닛1 Type:0 MaxHP:100
유닛3 Type:0 MaxHP:100
유닛9 Type:0 MaxHP:100
유닛10 Type:1 MaxHP:50
유닛15 Type:1 MaxHP:50
유닛19 Type:1 MaxHP:50
flyweight패턴
사용상황 : 디팬스 게임에서 내가 정중앙에 있고 적들이 사방에서 엄청 몰려올 때, 적의 수 만큼 데이터가 필요하다.
너무 많은 데이터가 필요하다면 공통된 정보는 공유해서 사용하는 방법이 Flyweight 패턴이다.
위 예제는 타입, 최대hp, 공격력, 방어력이 유닛타입(전사, 마법사) 에 따라 같다고 했을 때, 이는 공통되는 속석이므로,
공통되는 속성을 Flyweight로 묶어서 Unit이 참조하게 만들었다.
'이전게시판 > C, C++' 카테고리의 다른 글
c++ 전처리기 region 이란 (0) | 2018.09.30 |
---|---|
pragma message 출력창에 내용 출력 (0) | 2018.08.29 |
Cygwin 설치 설정 방법 (0) | 2018.07.27 |
서버 파싱 중 이진수 데이터 조합 (0) | 2018.06.20 |
VisualStudio 줄번호 바로가기 단축키 (0) | 2018.06.05 |
const와 포인터 (0) | 2018.05.30 |
C3083 왼쪽의 기호는 형식이어야 합니다 에러 정방선언... (0) | 2018.05.03 |
typedef한 자료형의 별명을 리턴값으로 사용시 에러... (0) | 2018.04.26 |
Post
VisualStudio 줄번호 바로가기 단축키 : Ctrl + G
'이전게시판 > C, C++' 카테고리의 다른 글
pragma message 출력창에 내용 출력 (0) | 2018.08.29 |
---|---|
Cygwin 설치 설정 방법 (0) | 2018.07.27 |
서버 파싱 중 이진수 데이터 조합 (0) | 2018.06.20 |
flyweight(플라이웨이트) 패턴 (0) | 2018.06.16 |
const와 포인터 (0) | 2018.05.30 |
C3083 왼쪽의 기호는 형식이어야 합니다 에러 정방선언... (0) | 2018.05.03 |
typedef한 자료형의 별명을 리턴값으로 사용시 에러... (0) | 2018.04.26 |
프로토콜, 라우터 (0) | 2018.04.19 |
Post
tortoisesvn Path : 내가 A에서 작업한 내용을 B폴더로 가져가서 작업할 때 유용
A폴더를 마우스 오른쪽 클릭 - tortoiseSVN - Create Path
패치 파일 생성.
이제 B폴더로 안으로 들어가서 - tortoiseSVN - Apply Path - All Item
A폴더는 변경된 파일을 모두 가지고 있는 폴더
B폴더도 마찬가지지. 다만 패치 생성 때는 폴더 안에 들어 Apply Path를 해야함.
'etc' 카테고리의 다른 글
클립스튜디오 자기 브러쉬 등록하는 법 (0) | 2024.05.06 |
---|---|
VBA 오류들 (0) | 2018.06.22 |
No bootable medium found ( VirtualBox Window 10 설치 ) (0) | 2018.05.09 |
[R데이터]네이버 뉴스 크롤링 (0) | 2018.01.09 |
R 기초 - 프로그램 설치 (0) | 2018.01.09 |
래퍼런스, 포인터 차이, 프로시저 사용이유, 외래키? (0) | 2016.04.07 |
Post
const : 변수가 상수가 되도록 정의하는 키워드
* 함수의 인자에 const 키워드를 선언한다면 구현 부분에도 const를 추가한다
선언부
void PrintNumber(const int nValue);
구현부
void PrintNumber(const int nValue)
{
printf("%d \n", nValue);
}
* 멤버변수의 값이 멤버함수 내에서 변경되지 않도록 만들려면 함수 선언 맨 뒤에 const를 추가한다.
(지역변수는 const 함수 내에서도 값 변경이 된다)
선언부
class Level
{
int nLevel = 0;
public:
// 함수안에서 값을 변경할 수 없을 때
void SetLevel(int nValue) const;
};
구현부
void Level::SetLevel(int nValue) const
{
int temp = nValue;
//nLevel = nValue;
}
* const 키워드를 포인터 변수에 사용할 시 위치에 따라 의미가 달라진다.
const int* p = &a;
const가 맨 앞에 있는 경우 : 포인터가 가르키는 변수의 값을 변경시키지 못한다.
*p = 22; (X)
int* const p = &a;
'이전게시판 > C, C++' 카테고리의 다른 글
Cygwin 설치 설정 방법 (0) | 2018.07.27 |
---|---|
서버 파싱 중 이진수 데이터 조합 (0) | 2018.06.20 |
flyweight(플라이웨이트) 패턴 (0) | 2018.06.16 |
VisualStudio 줄번호 바로가기 단축키 (0) | 2018.06.05 |
C3083 왼쪽의 기호는 형식이어야 합니다 에러 정방선언... (0) | 2018.05.03 |
typedef한 자료형의 별명을 리턴값으로 사용시 에러... (0) | 2018.04.26 |
프로토콜, 라우터 (0) | 2018.04.19 |
C3867 비표준 구문입니다. &를 사용하여 멤버 포인터를 만드세요 (0) | 2018.04.17 |
Post
애니메이션 끝나고 함수 호출하는 법
해당 애니메이션 더블클릭
=>Inspector-Animation-Event에서
Function에 호출할 함수 이름을 적는다.
'이전게시판 > Unity' 카테고리의 다른 글
유니티 안드로이드 빌드 (0) | 2018.05.19 |
---|---|
유니티 버튼 클릭 이벤트 (0) | 2018.05.17 |
유니티 Button OnClick 이벤트 (0) | 2018.05.17 |
RayCast 위치와 실제 내가 클릭하는 위치가 다를때... (0) | 2018.05.06 |
Unity Anchors(앵커) (0) | 2018.05.05 |
유니티 2D충돌체크, 코루틴 (0) | 2018.04.29 |
유니티 스프라이트2D (0) | 2018.04.28 |
유니티 네비게이션, 파티클 (0) | 2018.04.22 |
Post
BuildSetting=>PlayerSetting
Other Setting
Identification 중요
앞에있는 버전 : 실행파일 버전(환경이 바뀌었을 때.. 구글스토어 업뎃)
뒤에(Bundle Version Code) : 데이터바뀔 때 (게임에서 업뎃)
Minimum API Level : 최소버전..어느버전서부터호환시킬것인지?
Target API Level : 권장사항
Resoultion and Presention
Defualt Orientation : AutoRotion (막돌아감)
Splash Image : 로고(공짜면 로그인 로그 안없어짐)
publishing Settings : 퍼블리싱 키 코드받아서 작업..(예를들어 n스토어면 n스토어 키)
Unity Proferense
유니티 5.6 버전 => jdk Java SE 8u171/ 8u172 다운
설치 위치를 넣어주면 된다
sdk위치 : C:/Users/Administrator.Sc-201712221631/AppData/Local/Android/Sdk
jdk위치 : C:/Program Files/Java/jdk1.8.0_161
====================================
3D애니메이션과 프리팹은 다름
=> 3D애니메이션은 transform이 아니라 모델 다체의 스케일 팩터를 수정해야한다!
'이전게시판 > Unity' 카테고리의 다른 글
애니메이션 끝나고 함수 호출하는 법 (0) | 2018.05.20 |
---|---|
유니티 버튼 클릭 이벤트 (0) | 2018.05.17 |
유니티 Button OnClick 이벤트 (0) | 2018.05.17 |
RayCast 위치와 실제 내가 클릭하는 위치가 다를때... (0) | 2018.05.06 |
Unity Anchors(앵커) (0) | 2018.05.05 |
유니티 2D충돌체크, 코루틴 (0) | 2018.04.29 |
유니티 스프라이트2D (0) | 2018.04.28 |
유니티 네비게이션, 파티클 (0) | 2018.04.22 |