Work/PSP
[PSP_DEV 4_1] PSP와 통신을 해보자! 서버편
kevin.
2007. 1. 8. 20:34
PSPSDK Sample을 보면 PSP를 서버로 사용한 echo server가 있습니다.
요것을 조금 변형하여 PC에 TCP 서버를 심고, PSP에서 PC에 접속하여 PSP의 버튼이 눌릴때마다
PC에게 그 사실을 알려주는 프로그램을 작성해보도록 하겠습니다.
사실 이 자체로만은 아주 쓸모가 없지만(ㅡ,.ㅡ;;) 먼가 응용해보면 멋진것이 나올지도 모를일이죠 ^^
그럼 먼저 PC에서 실행시킬 서버 코드를 살펴보겠습니다.
서버는 Win32 API로 작성하였습니다.
#include <windows.h>
#include <process.h>
#include <stdio.h>
#include <process.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
#define ID_EDIT 101
#define ID_START 102
#define ID_STATUS 103
#define ID_MSG 104
#define ID_START 102
#define ID_STATUS 103
#define ID_MSG 104
#define ID_LEFT 500
#define ID_RIGHT 501
#define ID_RIGHT 501
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
HINSTANCE g_hInst;
LPSTR lpszClass="PSPCtrlServer";
HINSTANCE g_hInst;
LPSTR lpszClass="PSPCtrlServer";
/*
* 각 control들을 위한 핸들입니다.
* 이 핸들은 각 control을 제어하기 위하여 사용됩니다.
*/
HWND hStart;
HWND hStatus;
HWND hMessage;
* 각 control들을 위한 핸들입니다.
* 이 핸들은 각 control을 제어하기 위하여 사용됩니다.
*/
HWND hStart;
HWND hStatus;
HWND hMessage;
#define IS_SOCKET_INVALID(x) ((x) == INVALID_SOCKET)
#define IS_SOCKET_ERROR(x) ((x) == SOCKET_ERROR)
#define IS_SOCKET_ERROR(x) ((x) == SOCKET_ERROR)
/*
* PSP가 보내온 메세지를 분석하여 화면에 출력해 줍니다.
* str은 키를 정말 짧게 누르지 않는 이상 여러 문자가 전송됩니다.
* 예를 들어 네모를 누른경우 SQUARESQUARESQUARE 이런식으로 전송됩니다.
* 편의상 처음 한개의 값만 받아들이기 위해 처음 글자들만 비교하도록 합니다.
*/
void parseMsg(char* str, int len)
{
if(!strncmp(str, "SQUARE", 6))
{
SetWindowText(hMessage, "SQUARE");
}
if(!strncmp(str, "TRIANGLE", 8))
{
SetWindowText(hMessage, "TRIANGLE");
}
if(!strncmp(str, "CIRCLE", 6))
{
SetWindowText(hMessage, "CIRCLE");
}
if(!strncmp(str, "CROSS", 5))
{
SetWindowText(hMessage, "CROSS");
}
* PSP가 보내온 메세지를 분석하여 화면에 출력해 줍니다.
* str은 키를 정말 짧게 누르지 않는 이상 여러 문자가 전송됩니다.
* 예를 들어 네모를 누른경우 SQUARESQUARESQUARE 이런식으로 전송됩니다.
* 편의상 처음 한개의 값만 받아들이기 위해 처음 글자들만 비교하도록 합니다.
*/
void parseMsg(char* str, int len)
{
if(!strncmp(str, "SQUARE", 6))
{
SetWindowText(hMessage, "SQUARE");
}
if(!strncmp(str, "TRIANGLE", 8))
{
SetWindowText(hMessage, "TRIANGLE");
}
if(!strncmp(str, "CIRCLE", 6))
{
SetWindowText(hMessage, "CIRCLE");
}
if(!strncmp(str, "CROSS", 5))
{
SetWindowText(hMessage, "CROSS");
}
if(!strncmp(str, "UP", 2))
{
SetWindowText(hMessage, "UP");
}
if(!strncmp(str, "DOWN", 4))
{
SetWindowText(hMessage, "DOWN");
}
if(!strncmp(str, "LEFT", 4))
{
SetWindowText(hMessage, "LEFT");
}
if(!strncmp(str, "RIGHT", 5))
{
SetWindowText(hMessage, "RIGHT");
}
{
SetWindowText(hMessage, "UP");
}
if(!strncmp(str, "DOWN", 4))
{
SetWindowText(hMessage, "DOWN");
}
if(!strncmp(str, "LEFT", 4))
{
SetWindowText(hMessage, "LEFT");
}
if(!strncmp(str, "RIGHT", 5))
{
SetWindowText(hMessage, "RIGHT");
}
if(!strncmp(str, "START", 5))
{
SetWindowText(hMessage, "");
}
{
SetWindowText(hMessage, "");
}
if(!strncmp(str, "SELECT", 6))
{
SetWindowText(hMessage, "SELECT");
}
if(!strncmp(str, "NOTE", 4))
{
SetWindowText(hMessage, "NOTE");
}
if(!strncmp(str, "LTRIGGER", 8))
{
SetWindowText(hMessage, "LTRIGGER");
}
if(!strncmp(str, "RTRIGGER", 8))
{
SetWindowText(hMessage, "RTRIGGER");
}
}
{
SetWindowText(hMessage, "SELECT");
}
if(!strncmp(str, "NOTE", 4))
{
SetWindowText(hMessage, "NOTE");
}
if(!strncmp(str, "LTRIGGER", 8))
{
SetWindowText(hMessage, "LTRIGGER");
}
if(!strncmp(str, "RTRIGGER", 8))
{
SetWindowText(hMessage, "RTRIGGER");
}
}
void serverThread(void* param)
{
const int PACKET_SIZE = 8 * 1024;
const int BIND_PORT = 21000;
{
const int PACKET_SIZE = 8 * 1024;
const int BIND_PORT = 21000;
/* server socket을 생성합니다. */
SOCKET s_ = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htons(INADDR_ANY);
saddr.sin_port = htons(BIND_PORT);
if (IS_SOCKET_ERROR(bind(s_, (struct sockaddr*)&saddr, sizeof(saddr))))
printf("bind error\n");
if (IS_SOCKET_ERROR(listen(s_, 5)))
printf("listen error\n");
SOCKET s_ = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htons(INADDR_ANY);
saddr.sin_port = htons(BIND_PORT);
if (IS_SOCKET_ERROR(bind(s_, (struct sockaddr*)&saddr, sizeof(saddr))))
printf("bind error\n");
if (IS_SOCKET_ERROR(listen(s_, 5)))
printf("listen error\n");
struct sockaddr_in caddr;
int cbAddr = sizeof(caddr);
/* client 접속을 대기합니다. */
SOCKET c_ = accept(s_, (struct sockaddr*)&caddr, &cbAddr);
if (IS_SOCKET_INVALID(c_))
printf("accept error\n");
/* 접속이 완료되면 아래의 메세지를 출력합니다. */
SetWindowText(hStatus, "Client Connected!!!");
int cbAddr = sizeof(caddr);
/* client 접속을 대기합니다. */
SOCKET c_ = accept(s_, (struct sockaddr*)&caddr, &cbAddr);
if (IS_SOCKET_INVALID(c_))
printf("accept error\n");
/* 접속이 완료되면 아래의 메세지를 출력합니다. */
SetWindowText(hStatus, "Client Connected!!!");
int len;
char inbuf_[PACKET_SIZE] = "";
while ((len = recv(c_, inbuf_, sizeof(inbuf_), 0)) > 0)
{
parseMsg(inbuf_, len);
}
char inbuf_[PACKET_SIZE] = "";
while ((len = recv(c_, inbuf_, sizeof(inbuf_), 0)) > 0)
{
parseMsg(inbuf_, len);
}
closesocket(c_);
closesocket(s_);
closesocket(s_);
return;
}
}
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance
,LPSTR lpszCmdParam,int nCmdShow)
{
HWND hWnd;
MSG Message;
WNDCLASS WndClass;
g_hInst=hInstance;
WndClass.cbClsExtra=0;
WndClass.cbWndExtra=0;
WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
WndClass.hInstance=hInstance;
WndClass.lpfnWndProc=(WNDPROC)WndProc;
WndClass.lpszClassName=lpszClass;
WndClass.lpszMenuName=NULL;
WndClass.style=CS_HREDRAW | CS_VREDRAW;
RegisterClass(&WndClass);
,LPSTR lpszCmdParam,int nCmdShow)
{
HWND hWnd;
MSG Message;
WNDCLASS WndClass;
g_hInst=hInstance;
WndClass.cbClsExtra=0;
WndClass.cbWndExtra=0;
WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
WndClass.hInstance=hInstance;
WndClass.lpfnWndProc=(WNDPROC)WndProc;
WndClass.lpszClassName=lpszClass;
WndClass.lpszMenuName=NULL;
WndClass.style=CS_HREDRAW | CS_VREDRAW;
RegisterClass(&WndClass);
hWnd=CreateWindow(lpszClass,"PSP Ctrl Server",WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT, 200, 150, NULL,(HMENU)NULL,hInstance,NULL);
ShowWindow(hWnd,nCmdShow);
CW_USEDEFAULT,CW_USEDEFAULT, 200, 150, NULL,(HMENU)NULL,hInstance,NULL);
ShowWindow(hWnd,nCmdShow);
while(GetMessage(&Message,0,0,0)) {
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return Message.wParam;
}
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return Message.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
switch(iMessage) {
case WM_CREATE:
/* 소켓을 초기화 합니다. */
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
/* Start Button을 생성합니다. */
hStart = CreateWindow("button", "Start", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
20, 10, 50, 25, hWnd, (HMENU)ID_START, g_hInst, NULL);
/* 진행상황과 전달된 버튼의 종류가 표시될 static control을 생성합니다. */
hStatus = CreateWindow("static", "Not connected", WS_CHILD | WS_VISIBLE,
20, 50, 150, 25, hWnd, (HMENU)ID_STATUS, g_hInst, NULL);
hStart = CreateWindow("button", "Start", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
20, 10, 50, 25, hWnd, (HMENU)ID_START, g_hInst, NULL);
/* 진행상황과 전달된 버튼의 종류가 표시될 static control을 생성합니다. */
hStatus = CreateWindow("static", "Not connected", WS_CHILD | WS_VISIBLE,
20, 50, 150, 25, hWnd, (HMENU)ID_STATUS, g_hInst, NULL);
hMessage = CreateWindow("static", "", WS_CHILD | WS_VISIBLE,
20, 70, 150, 25, hWnd, (HMENU)ID_MSG, g_hInst, NULL);
return 0;
case WM_DESTROY:
/* 윈도우가 닫힐 때, 소켓 관련하여 열어둔것을 닫기 위해 WSACleanup을 불러줍니다. */
WSACleanup();
PostQuitMessage(0);
return 0;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_START:
/*
* ID_START Button을 클릭했을 경우 serverThread를 시작하고,
* Start 버튼을 화면에서 안보이도록 합니다.
*/
_beginthread(serverThread, 0, 0);
ShowWindow(hStart, SW_HIDE);
break;
}
return 0;
20, 70, 150, 25, hWnd, (HMENU)ID_MSG, g_hInst, NULL);
return 0;
case WM_DESTROY:
/* 윈도우가 닫힐 때, 소켓 관련하여 열어둔것을 닫기 위해 WSACleanup을 불러줍니다. */
WSACleanup();
PostQuitMessage(0);
return 0;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_START:
/*
* ID_START Button을 클릭했을 경우 serverThread를 시작하고,
* Start 버튼을 화면에서 안보이도록 합니다.
*/
_beginthread(serverThread, 0, 0);
ShowWindow(hStart, SW_HIDE);
break;
}
return 0;
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
간단한 TCP 서버입니다. 만약 recv에서 고대로 send 해준다면 TCP Echo 서버가 되겠지요.
이 서버는 다중 접속을 허용하지 않습니다.
왜냐믄 귀찮아서 하나만 접속하도록 만들었기 때문이죠 ㅡㅡ;;
이 소스를 돌려보실 분은 VC에서 다음을 설정해주셔야 합니다.
Project->Setting->C/C++->Category : Code Generation->USe run-time library : Multithreaded.