http://www.sockaddr.com/ExampleSourceCode.html
바로 받기
- 원본 코드
- 새로 친 코드
변경 내용 - 약간의 한글화
코드 보기
- 클라이언트 (winsock_3_1)
/*
출처 및 저작권 표기(Copyright)
http://www.sockaddr.com/ExampleSourceCode.html
http://cakel.tistory.com
교육용을 목적으로 자유롭게 쓰실수 있습니다.
tcp_client.cpp (Client.cpp)
아주 간단한 스트림 클라이언트 예제 입니다.
udp_server.cpp (Server.cpp)와 같이 작동합니다.
이 프로그램은 명령줄에 있는 서버와 포트명에 접속을 시도합니다.
서버 프로그램은 시작 되었을때 필요한 정포를 표시합니다.
연결이 되면 서버에 접속해서 자료를 보내고 응답을 기다린후 종료 합니다.
wsock32.lib 와 함께 링크하시고 컴파일 하세요
서버명과 포트 번호를 명령줄에 넣어 주세요
예 : udp_client 127.0.0.1 2000
*/
#include <stdio.h>
#include <winsock.h>
// 함수 프로토타입
void StreamClient(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);
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;
}
// 스트림 클라이언트가 해야 할 일을 합니다.
// 여기까지는 UDP 와 크게 차이가 없습니다.
StreamClient(argv[1], nPort);
WSACleanup();
return 0;
}
//
void StreamClient(char* szServer, short nPort)
{
printf("\n스트림 클라이언트가 서버 : %s 포트 : %d 에 접속합니다", szServer, nPort);
// 서버를 찾습니다.
LPHOSTENT lpHostEntry;
lpHostEntry = gethostbyname(szServer);
if(lpHostEntry == NULL)
{
PRINTERROR("gethostbyname()");
return;
}
// TCP/IP 스트림 소켓을 생성합니다.
SOCKET theSocket;
// socket(주소 계열, 소켓 형태, 프로토콜
theSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
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); // 명령줄에서 포트 번호를 받습니다.
// 서버로 접속합니다
int nRet;
// connect(소켓, 서버 주소, 서버 주소의 길이
nRet = connect(theSocket, (LPSOCKADDR)&saServer, sizeof(struct sockaddr) );
if(nRet == SOCKET_ERROR)
{
PRINTERROR("socket()");
closesocket(theSocket);
return;
}
// 서버로 자료를 보냅니다.
char szBuf[256];
strcpy(szBuf, "클라이언트에서 보내는 TCP 값입니다");
// Windows 에서는 Unix 계열과 다르게 보낼때 write 대신에 send 를 씁니다.
// send(연결된 소켓, 보낼 자료 버퍼, 자료의 길이, 상태값
nRet = send(theSocket, szBuf, strlen(szBuf), 0);
if (nRet == SOCKET_ERROR)
{
PRINTERROR("send()");
closesocket(theSocket);
return;
}
// 응답을 기다립니다
// Windows 에서는 Unix 계열과 다르레 받을때는 read 대신에 recv 를 씁니다.
// recv(연결된 소켓, 받은 자료를 저장할 버퍼, 버퍼의 길이, 상태값)
nRet = recv(theSocket, szBuf, sizeof(szBuf), 0);
if (nRet == SOCKET_ERROR)
{
PRINTERROR("recv()");
closesocket(theSocket);
return;
}
// 받은 값을 표시합니다.
printf("\n값을 받았습니다 : %s", szBuf);
closesocket(theSocket);
return;
}
- 서버(winsock_3_2)
/*
저작권 표기(Copyrights)
http://www.sockaddr.com/ExampleSourceCode.html
http://cakel.tistory.com
교육용을 목적으로 자유롭게 쓰실수 있습니다.
아주 간단한 스트림 서버 예제 입니다.
udp_client (Client.cpp) 와 작동 합니다.
이 프로그램은 TCP 프로토콜을 이용해서 서버를 만드는 일을 합니다.
클라이언트에서 자료를 기다리고 들어온 값을 표기하며 클라이언트에게 값을
되돌리고 종료를 합니다.
wsock32.lib 를 링크 시키기고 컴파일 하세요
bind() 함수를 사용하기 위해 명령줄에 포트 번호를 넣어 주세요. 이미 쓰고 있지
않는다면 어떤 포트 번호도 쓸수 있습니다.
예 : udp_server 2000
*/
#include <stdio.h>
#include <winsock.h>
// 프로토타입 함수
void StreamServer(short nPort);
// 오류를 표기하는 매크로 도우미
#define PRINTERROR(s) fprintf( stderr, "%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;
}
// 스트림 서버가 할일을 수행합니다.
StreamServer(nPort);
return 0;
// 소켓을 풉니다.
WSACleanup();
}
void StreamServer(short nPort)
{
// TCP/IP 스트림 소켓을 "listen"으로 생성합니다.
SOCKET listenSocket;
// socket(주소계열, 소켓 형식, 프로토콜)
listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listenSocket == 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); // 명령줄에서 받은 포트를 넣습니다.
// 소켓과 listensocket 을 bind(묶습) 합니다.
int nRet;
// bind(소켓, 서버 주소, 주소 구조체의 길이
nRet = bind(listenSocket, (LPSOCKADDR)&saServer, sizeof(struct sockaddr) );
if(nRet == SOCKET_ERROR)
{
PRINTERROR("bind()");
closesocket(listenSocket);
return;
}
/*
이 부분은 잘 쓰이거나 요구되지 않습니다만, 이 예제에서 우리는 서버가 기다리고 있다는 것을
표시해줘야지 클라이언트가 접속할수 있어서 표시합니다.
*/
int nLen;
nLen = sizeof(SOCKADDR);
char szBuf[256];
nRet = gethostname( szBuf, sizeof(szBuf) );
if (nRet == SOCKET_ERROR)
{
PRINTERROR("gethostname()");
closesocket(listenSocket);
return;
}
// 서버 주소와 포트 번호를 표시 합니다.
printf("\n %s 서버가 %d 포트에서 요청을 기다립니다. \n", szBuf, nPort);
// 소켓에게 기다리게 합니다.
printf("\nlisten()");
// listen(오는 소켓, 요청 수용 가능한 용량)
nRet = listen(listenSocket, SOMAXCONN);
if(nRet == SOCKET_ERROR)
{
PRINTERROR("listen()");
closesocket(listenSocket);
return;
}
// 오는 요청을 기다립니다.
SOCKET remoteSocket;
printf("\naccept() 에서 막혔습니다.");
// accept(요청을 받으 소켓, 선택 클라이언트 주소)
remoteSocket = accept(listenSocket, NULL, NULL);
if(remoteSocket == INVALID_SOCKET)
{
PRINTERROR("accept()");
closesocket(listenSocket);
return;
}
/*
이제 클라이언트와 연결 했습니다.
새로운 소켓 식별자가 준비 되었다고 클라이언트 주소를 되돌림
값을 지고 왔습니다.
*/
// 클라이언트에서 값을 받습니다.
memset( szBuf, 0, sizeof(szBuf) );
nRet = recv(remoteSocket, szBuf, sizeof(szBuf), 0);
if (nRet == INVALID_SOCKET)
{
PRINTERROR("recv()");
closesocket(listenSocket);
closesocket(remoteSocket);
return;
}
// 받은 값을 표시 합니다.
printf("\n값을 받았습니다 : %s", szBuf);
// 클라이언트에게 값을 되돌려 줍니다.
strcpy(szBuf, "클라이언트로 값을 보냅니다. 잘받았습니다");
// send(연결된 소켓, 보낼 버퍼, 버퍼의 길이, 상태값)
nRet = send(remoteSocket, szBuf, sizeof(szBuf), 0);
// 소켓 둘다 닫습니다
closesocket(remoteSocket);
closesocket(listenSocket);
return;
}
출력 화면