http://www.sockaddr.com/ExampleSourceCode.html
바로 받기
원본
새로친거
수정 내용
1. 주석/부분 한글화
수행코드
- 클라이언트(winsock_2_1)
/*
저작권
http://www.sockaddr.com/ExampleSourceCode.html
http://cakel.tistory.com
교육용을 목적으로 자유롭게 배포가 가능합니다.
DClient.cpp (udp_client.cpp)
완전 쉽고, 쓸모 없는 데이터그램 클라이언트 예제 입니다.
DServer.cpp (udp_server.cpp) 와 같이 동작합니다.
이 프로그램은 명령줄에서 명시한 서버와 포트에 접속을 시도합니다.
DServer 프로그램은 시작할때 무슨 정보가 필요한지 표시합니다. 접속이 되면,
이 프로그램은 서버에게 전송을 하고 응답을 기다립니다.
wsock32.lib (ws2_32.lib) 와 같이 컴파일/링크 하세요
서버이름과 포트번호를 명령 줄에 넣어 보내줘야 합니다.
예제 : udp_client 127.0.0.1 2000
*/
#include <stdio.h>
#include <string.h>
#include <winsock.h>
// 프토타입 함수 선언
void DatagramClient(char* szServer, short nPort);
// 오류를 표시하기 위한 매크로 도우미 정의
#define PRINTERROR(s) fprintf(stderr, "\n%: &d\n", s, WSAGetLastError())
//
int main(int argc, char* *argv)
{
WORD wVersionRequested = MAKEWORD(1,1); // 윈속 버전 1.1을 요구 참고 : http://blog.naver.com/dreamset?Redirect=Log&logNo=60010620996
WSADATA wsaData;
int nRet;
short nPort;
// 호스트와 포트 인수를 검사합니다.
if (argc !=3)
{
fprintf(stderr, "\n문법 : udp_client [서버주소] [포트번호]\n");
return 1;
}
nPort = atoi(argv[2]);
// 윈속과 버전을 검사합니다.
nRet = WSAStartup(wVersionRequested, &wsaData);
if (wsaData.wVersion != wVersionRequested)
{
fprintf(stderr, "\n 틀린 윈속 버전입니다\n");
return 1;
}
// 데이터그램 클라이언트가 해야 할 일을 이제 시작합니다.
DatagramClient(argv[1], nPort);
// 윈속을 풉니다.
WSACleanup();
return 0;
}
void DatagramClient(char* szServer, short nPort)
{
printf("\n데이터그램 클라이언트는 지금 전송 중입니다. 서버 : %s 포트 : %d", szServer, nPort);
// 서버를 찾습니다.
LPHOSTENT lpHostEntry;
lpHostEntry = gethostbyname(szServer);
if (lpHostEntry == NULL)
{
PRINTERROR("gethostbyname()");
return;
}
// UDP/IP 데이터그램 소켓을 생성합니다.
SOCKET theSocket;
// socket(주소계열, 소켓형식, 프토토콜)
theSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (theSocket == INVALID_SOCKET)
{
PRINTERROR("socket()");
return;
}
// 서버에게 보낼 주소 구조체를 채웁니다.
SOCKADDR_IN saServer;
saServer.sin_family = AF_INET;
saServer.sin_addr = *( (LPIN_ADDR)*lpHostEntry->h_addr_list); // 서버 주소
saServer.sin_port = htons(nPort); // 명령줄에서 포트 번호를 받은 것입니다.
// 서버에 자료를 전송합니다.
char szBuf[256];
int nRet;
strcpy(szBuf, "클라이언트에서 보냅니다. 잘가죠?");
// sendto(소켓,자료버퍼,자료의 길이, 플래그 - 상태값, 서버주소, 주소의 길이
nRet = sendto( theSocket, szBuf, strlen(szBuf), 0, (LPSOCKADDR)&saServer, sizeof(struct sockaddr) );
if(nRet == SOCKET_ERROR)
{
PRINTERROR("sendto()");
closesocket(theSocket);
return;
}
// 응답을 기다립니다.
memset(szBuf, 0, sizeof(szBuf));
int nFromLen;
nFromLen = sizeof(struct sockaddr);
// recvfrom(소켓, 받는버퍼, 버퍼의 길이, 플래그 - 상태값, 송신자의 주소를 받을 버퍼, 주소버퍼의 길이
recvfrom(theSocket, szBuf, sizeof(szBuf), 0, (LPSOCKADDR)&saServer, &nFromLen);
if(nRet == SOCKET_ERROR)
{
PRINTERROR("recvfrom()");
closesocket(theSocket);
return;
}
// 받은 값을 표시 합니다
printf("\nData received, 값을 받았습니다 : %s", szBuf);
closesocket(theSocket);
return;
}
- 서버(winsock_2_2)
/*
저작권
http://www.sockaddr.com/ExampleSourceCode.html
http://cakel.tistory.com
교육용을 목적으로 자유롭게 배포할수 있습니다.
udp_server.cpp (DServer.cpp)
아주 간단하고 쓸모 없는 데이터그램 서버 예지입니다.
udp_client.cpp (DClient.cpp)와 함께 작동합니다.
이 프로그램은 UDP 프로토콜을 이용하여 서버를 만듭니다. 그리고
클라이언트를 기다리며 들어 오는 데이터를 화면에 표시하고,
클라이언트에게 응답을 보내며 종료합니다.
wsock32.lib (ws2_32.lib) 와 함께 링크 하고 컴파일 하세요
bind() 함수를 쓰기 위해 명령줄에 포트 번호를 넣어 주세요.
쓰지 않는 어떤 포트 번호로 가능합니다.
예제 : udp_server 2000
*/
#include <stdio.h>
#include <winsock.h>
// 프로토타입 함수
void DatagramServer(short nPort);
// 오류를 표기하기 위한 매크로 도우미
#define PRINTERROR(s) fprintf(stderr, "\n%: %d\n", s, WSAGetLastError())
//
int main(int argc, char** argv)
{
WORD wVersionRequested = MAKEWORD(1, 1);
WSADATA wsaData;
int nRet;
short nPort;
// 인수를 점검합니다
if (argc != 2)
{
fprintf(stderr, "\n사용법 : udp_server [포트번호]\n");
return 1;
}
nPort = atoi(argv[1]);
// 윈속의 버전을 확인
nRet = WSAStartup(wVersionRequested, &wsaData);
if (wsaData.wVersion != wVersionRequested)
{
fprintf(stderr,"\n틀린 윈속 버전입니다.\n");
return 1;
}
// 이제 서버가 할 일을 실행합니다.
DatagramServer(nPort);
// 윈속을 풉니다.
WSACleanup();
return 0;
}
//
void DatagramServer(short nPort)
{
// UDP/IP 데이터 소켓을 생성합니다.
SOCKET theSocket;
// socket(주소계열, 소켓형식, 프로토콜)
theSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(theSocket == INVALID_SOCKET)
{
PRINTERROR("socket()");
return;
}
// 주소 구조체를 채웁니다.
SOCKADDR_IN saServer;
saServer.sin_family = AF_INET;
saServer.sin_addr.s_addr = INADDR_ANY; // 윈속이 정하게 해줍니다.
saServer.sin_port = htons(nPort); // 사용자에게서 포트 번호를 받습니다.
// 소켓으로 묶습니다.
int nRet;
// bind(소켓 기술자, 묶을 주소, 주소의 길이
nRet = bind( theSocket, (LPSOCKADDR)&saServer, sizeof(struct sockaddr) );
if (nRet == SOCKET_ERROR)
{
PRINTERROR("bind()");
closesocket(theSocket);
return;
}
/*
이 부분은 정상적으로 되지않거나 필요하지 않지만
이 예제에서 우리는 서버가 예제 클라이언트로 접속하기 위해
서버가 기다리고 있다는 것을 표시합니다.
*/
int nLen;
nLen = sizeof(SOCKADDR);
char szBuf[256];
nRet = gethostname(szBuf, sizeof(szBuf));
if (nRet == SOCKET_ERROR)
{
PRINTERROR("getthehostname()");
closesocket(theSocket);
return;
}
// 서버이름과 포트 번호를 표기 합니다.
printf("\n서버 이름이 %s 이(가) 포트번호 %d\n 에서 요청을 기다립니다.", szBuf, nPort);
// 클라이언트에서 오는 자료를 기다립니다.
SOCKADDR_IN saClient;
memset(szBuf, 0, sizeof(szBuf));
// recvfrom(응답할 소켓, 받은 버퍼, 버퍼의 바이트수, 플래그 - 상태값,
// 클라이언트 주소에서 받는 버퍼, 클라이언트 주소 버퍼의 길이
nRet = recvfrom(theSocket, szBuf, sizeof(szBuf), 0, (LPSOCKADDR)&saClient, &nLen);
// 이제 어떤 자료를 받았습니다.
printf("값을 받았습니다 : %s", szBuf);
// 클라이언트로 값을 돌려 줍니다.
strcpy(szBuf, "서버에서");
// sendto(보낼 소켓, 보낼 버퍼, 버퍼의 바이트수, 플래그 - 상태값,
// 자료를 보낼 주소, 주소의 길이
sendto(theSocket, szBuf, strlen(szBuf), 0, (LPSOCKADDR)&saClient, nLen);
/*
일반적으로 서버는 계속 작동을 해야지 다른 클라이언트들의 요청을 받습니다.
이 예제에서 하나의 요청(transaction, 트랜잭션, 거래)이 완료 되자 마자
종료 합니다.
*/
closesocket(theSocket);
return;
}
실행화면
서버 수행시 WinXP SP2 에서 방화벽 경고가 나오면 1차적으로 성공했습니다.
원본 코드와도 완벽하게 맞아 들어갑니다.
물론 새로 만든 코드와도 맞아 들어가죠
포트가 열려 있는걸 보실수 있습니다.