#include "winsock2.h"
#include "stdio.h"
#pragma comment( lib, "ws2_32.lib" )
#define BUFMAX 256
void err_handler(char *);
DWORD WINAPI Connection(LPVOID);
int main(int argc, char **argv)
{
int retval; // 임시로 값을 받을 정수형 변수
HANDLE hThread; // 스레드를 받을 핸들
DWORD ThreadId; // 스레드 ID를 받을 변수
// 윈속 초기화
// WSAStartup을 통해서 ws2_32.dll을 로딩하여 윈속을 사용할 수 있도록 초기화 함.
WSADATA wsa;
if( WSAStartup( MAKEWORD(2, 2), &wsa ) != 0)
{
return -1; // 윈속 초기화 실패시 종료(-1)
}
// 소켓 생성 socket()
SOCKET serv_sock = socket(AF_INET, SOCK_STREAM, 0);
if( serv_sock == INVALID_SOCKET ) err_handler("socket()");
// bind()
SOCKADDR_IN serv_addr;
ZeroMemory( &serv_addr, sizeof(serv_addr) );
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(9000);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
retval = bind(serv_sock, (SOCKADDR *)&serv_addr, sizeof(serv_addr));
if( retval == SOCKET_ERROR ) err_handler("bind()");
// listen()
retval = listen( serv_sock, SOMAXCONN );
if(retval == SOCKET_ERROR) err_handler("listen()");
// 클라이언트에 사용될 변수 선언
SOCKET clnt_sock;
SOCKADDR_IN clnt_addr;
int clnt_addr_size;
while(TRUE)
{
//accept()
clnt_addr_size = sizeof(clnt_addr);
clnt_sock = accept( (SOCKET)serv_sock, (SOCKADDR *)&clnt_addr, &clnt_addr_size );
if( clnt_sock == INVALID_SOCKET )
{
err_handler("accept()");
continue; // accept 실패하면 다시 accept에서 대기
}
// Thread 생성
hThread = CreateThread( NULL, 0, Connection, (LPVOID)clnt_sock, 0, &ThreadId );
if( hThread == NULL ) err_handler("Could not create Thread.");
}
// 소켓 닫기
closesocket( serv_sock );
// WSA 닫기
WSACleanup();
return 0;
}
void err_handler(char *msg)
{
printf("%s에서 에러가 발생하였습니다!\n", msg);
}
DWORD WINAPI Connection(LPVOID arg)
{
SOCKET clnt_sock = (SOCKET)arg;
int retval = 0; // 임시로 결과값을 저장하기 위한 변수
bool onoff = false; // 서버를 시작하는데 필요한 변수(onoff 스위치)
char buffer[BUFMAX+1] = {0}; // 소켓에서 사용할 버퍼
char bufpw[BUFMAX+1] = {0}; // 패스워드와 명령어를 임시적으로 저장하기 위한 버퍼
char file_buffer[BUFMAX+1] = {0}; // 파일 전송을 위해 사용할 버퍼
// clnt_sock <- 클라이언트 소켓만 가지고 getpeername을 이용해서
// 클라이언트의 아이피와 포트번호를 알아낸다.
SOCKADDR_IN clnt_addr;
int clnt_addr_size = sizeof( clnt_addr );
ZeroMemory( &clnt_addr, clnt_addr_size );
getpeername( clnt_sock, (SOCKADDR *)&clnt_addr, &clnt_addr_size );
// 패스워드 묻는 과정을 3번하기 위한 for 문장
for( int i = 0; i < 3; i++ )
{
ZeroMemory( bufpw, sizeof(bufpw) ); // 패스워드를 받기 위한 버퍼 초기화
printf("%s:%d에 패스워드를 요청합니다.\n", inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));
// 패스워드 묻는 프롬프트 출력(-> 클라이언트 화면)
strcpy( buffer, "\r\npassword : " );
retval = send( clnt_sock, buffer, BUFMAX, 0 );
if( retval == SOCKET_ERROR )
{
err_handler("send()"); // 에러출력 함수에 send() 값 전달
closesocket( clnt_sock );
return -1;
}
// 클라이언트에서 패스워드를 받아서 bufpw에 담는 부분
while( TRUE )
{
retval = recv( clnt_sock, buffer, BUFMAX, 0 );
if( retval == SOCKET_ERROR ) err_handler("passwd recv()");
if( buffer[retval-1] == '\n' ) break; // 엔터를 입력하면 빠져 나감.
else strncat( bufpw, buffer, retval );
}
printf("패스워드를 입력받습니다 : %s\n", bufpw);
// 입력받은 패스워드 비교 부분
char *password = "mypass";
int password_size = (int)strlen(password);
int bufpw_size = (int)strlen(bufpw);
// 길이를 먼저 비교해보고 맞으면 길이만큼 패스워드 비교
// 패스워드가 맞으면 onoff = true 넣어주고, 틀리면 계속 진행
// printf("bufpw %d, password %d\n", bufpw_size, password_size);
if( !((bufpw_size == password_size) && (strncmp(bufpw, password, password_size) == 0)) ) continue;
else
{
onoff = true; // 서버를 시작하기 위해 true 값을 설정
break; // 패스워드 3회 체크 for문 탈출
}
} // for 패스워드 3회 비교 부분
// 서버 시작부분 if 문
if( onoff == true )
{
// 클라이언트측에 환영 메시지 표시
char *welcome = "\r\nWelcome to Telnet server!\r\n";
retval = send(clnt_sock, welcome, (int)strlen(welcome), 0);
if( retval == SOCKET_ERROR ) err_handler("send to client end of line()");
// bufpw 버퍼를 명령어 버퍼로 재활용합니다.
ZeroMemory( bufpw, sizeof(bufpw) );
while( TRUE )
{
// buffer 버퍼를 초기화합니다.(초기화하지 않으면 쓰레기값이 많음)
ZeroMemory( buffer, sizeof(buffer) );
// recv()
retval = recv( clnt_sock, buffer, BUFMAX, 0 );
if( retval == SOCKET_ERROR )
{
err_handler("recv()"); // 에러출력 함수에 recv() 전달
break;
}
else if(retval == 0) break; // (retval == 0 정상 소켓 종료)
buffer[retval] = '\0'; // ZeroMemory 해서 하지 않아도 되지만 정석으로 하는 과정임.
//------------------------------------------------------//
// 위의 패스워드 입력 버퍼 복사 부분처럼 //
// while 문으로 쓰지 않아도 아래 if 문장이 엔터 입력을 //
// 받지 않으면 루프 반복되어서 while문을 따로 쓰지 않음.//
//------------------------------------------------------//
// buffer를 bufpw(명령어버퍼)에 복사한다.
strncat( bufpw, buffer, retval );
printf("%s", buffer);
// ---------------------------------------------------------------- //
// 엔터가 입력되면 네트워크로 \r\n 패킷이 온다. //
// 엔터 패킷만 왔을때에는 buffer[0]='\r', buffer[1]='\n'이 된다. //
// ---------------------------------------------------------------- //
if( buffer[retval-1] == '\n' )
{
// 엔터명령을 받은후 명령어 출력
printf( "입력받은 명령어 : %s", bufpw );
// 명령어 해석 / 실행 / 결과 전송
if( strncmp(bufpw, "exit", 4) == 0)
{
strcat( buffer, "<exit 명령어 실행 완료>" ); // 메시지 설정
strcat( buffer, "\r\n" ); // 클라이언트로 보낼 버퍼에 완료 메시지
printf( "%s\n", buffer ); // 서버에 완료 메시지 출력
retval = (int)strlen( buffer ); // 메시지 사이즈에 버퍼 크기를 맞춘다.
closesocket( clnt_sock ); // 소켓을 닫는다.
break;
} // if (exit 명령)
else if( strncmp(bufpw, "netstat", 7) == 0)
{
ShellExecute( NULL, "open", "cmd.exe", "/c netstat -an > netstat.txt", "c:\\", SW_HIDE );
strcat( buffer, "<netstat 명령어 실행 완료>" ); // 메시지 설정
strcat( buffer, "\r\n" ); // 클라이언트로 보낼 버퍼에 완료 메시지
printf( "%s\n", buffer ); // 서버에 완료 메시지 출력
retval = (int)strlen(buffer); // 메시지 사이즈에 버퍼 크기를 맞춘다.
FILE *read_file = fopen( "c:\\netstat.txt", "r" );// 읽을 파일의 포인터 선언
Sleep(1000); // 1초간 딜레이를 두어서 파일이 생성되기를 기다린다.
// 파일이 생성되지 않았을때 클라이언트에 메시지 출력
if (read_file == NULL)
{
char *msg = "결과 파일이 생성에 실패하였습니다.\r\n다시 시도해 주십시오.\r\n";
retval = send(clnt_sock, msg, (int)strlen(msg), 0);
if(retval == SOCKET_ERROR)
{
err_handler("netstat()");
break;
}
}
// 파일이 생성되었을 경우에 파일 내용을 보냄
else
{
while( (fgets(file_buffer, BUFMAX, read_file) != 0) )
{
strcat( file_buffer, "\r" ); // 한 라인이 끝나고 줄바꿈 표시
retval = send( clnt_sock, file_buffer, (int)strlen(file_buffer), 0 );
if( retval == SOCKET_ERROR )
{
err_handler("netstat()");
break;
}
} // while (fgets)
} // if_else 문장(파일 유무에 따른 절차)
fclose(read_file);
} // else if (netstat 명령)
//--------------------------------------------------//
// 명령어 수행 후 명령어 버퍼 초기화 및 계속 진행 //
// while() 시작에 초기화를 하면 되지만, //
// 이해를 돕기위해 명령어 수행 후 바로 버퍼 초기화 //
//--------------------------------------------------//
ZeroMemory( bufpw, sizeof(bufpw) );
}
// send()
retval = send( clnt_sock, buffer, retval, 0 );
if( retval == SOCKET_ERROR )
{
err_handler("send()");
break;
}
} // while문 recv() send()
} // if onoff 서버 본문
printf( "%s:%d에서의 클라이언트 연결을 끊습니다.\n", inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port) );
closesocket( clnt_sock );
return 0;
}
#include "stdio.h"
#pragma comment( lib, "ws2_32.lib" )
#define BUFMAX 256
void err_handler(char *);
DWORD WINAPI Connection(LPVOID);
int main(int argc, char **argv)
{
int retval; // 임시로 값을 받을 정수형 변수
HANDLE hThread; // 스레드를 받을 핸들
DWORD ThreadId; // 스레드 ID를 받을 변수
// 윈속 초기화
// WSAStartup을 통해서 ws2_32.dll을 로딩하여 윈속을 사용할 수 있도록 초기화 함.
WSADATA wsa;
if( WSAStartup( MAKEWORD(2, 2), &wsa ) != 0)
{
return -1; // 윈속 초기화 실패시 종료(-1)
}
// 소켓 생성 socket()
SOCKET serv_sock = socket(AF_INET, SOCK_STREAM, 0);
if( serv_sock == INVALID_SOCKET ) err_handler("socket()");
// bind()
SOCKADDR_IN serv_addr;
ZeroMemory( &serv_addr, sizeof(serv_addr) );
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(9000);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
retval = bind(serv_sock, (SOCKADDR *)&serv_addr, sizeof(serv_addr));
if( retval == SOCKET_ERROR ) err_handler("bind()");
// listen()
retval = listen( serv_sock, SOMAXCONN );
if(retval == SOCKET_ERROR) err_handler("listen()");
// 클라이언트에 사용될 변수 선언
SOCKET clnt_sock;
SOCKADDR_IN clnt_addr;
int clnt_addr_size;
while(TRUE)
{
//accept()
clnt_addr_size = sizeof(clnt_addr);
clnt_sock = accept( (SOCKET)serv_sock, (SOCKADDR *)&clnt_addr, &clnt_addr_size );
if( clnt_sock == INVALID_SOCKET )
{
err_handler("accept()");
continue; // accept 실패하면 다시 accept에서 대기
}
// Thread 생성
hThread = CreateThread( NULL, 0, Connection, (LPVOID)clnt_sock, 0, &ThreadId );
if( hThread == NULL ) err_handler("Could not create Thread.");
}
// 소켓 닫기
closesocket( serv_sock );
// WSA 닫기
WSACleanup();
return 0;
}
void err_handler(char *msg)
{
printf("%s에서 에러가 발생하였습니다!\n", msg);
}
DWORD WINAPI Connection(LPVOID arg)
{
SOCKET clnt_sock = (SOCKET)arg;
int retval = 0; // 임시로 결과값을 저장하기 위한 변수
bool onoff = false; // 서버를 시작하는데 필요한 변수(onoff 스위치)
char buffer[BUFMAX+1] = {0}; // 소켓에서 사용할 버퍼
char bufpw[BUFMAX+1] = {0}; // 패스워드와 명령어를 임시적으로 저장하기 위한 버퍼
char file_buffer[BUFMAX+1] = {0}; // 파일 전송을 위해 사용할 버퍼
// clnt_sock <- 클라이언트 소켓만 가지고 getpeername을 이용해서
// 클라이언트의 아이피와 포트번호를 알아낸다.
SOCKADDR_IN clnt_addr;
int clnt_addr_size = sizeof( clnt_addr );
ZeroMemory( &clnt_addr, clnt_addr_size );
getpeername( clnt_sock, (SOCKADDR *)&clnt_addr, &clnt_addr_size );
// 패스워드 묻는 과정을 3번하기 위한 for 문장
for( int i = 0; i < 3; i++ )
{
ZeroMemory( bufpw, sizeof(bufpw) ); // 패스워드를 받기 위한 버퍼 초기화
printf("%s:%d에 패스워드를 요청합니다.\n", inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));
// 패스워드 묻는 프롬프트 출력(-> 클라이언트 화면)
strcpy( buffer, "\r\npassword : " );
retval = send( clnt_sock, buffer, BUFMAX, 0 );
if( retval == SOCKET_ERROR )
{
err_handler("send()"); // 에러출력 함수에 send() 값 전달
closesocket( clnt_sock );
return -1;
}
// 클라이언트에서 패스워드를 받아서 bufpw에 담는 부분
while( TRUE )
{
retval = recv( clnt_sock, buffer, BUFMAX, 0 );
if( retval == SOCKET_ERROR ) err_handler("passwd recv()");
if( buffer[retval-1] == '\n' ) break; // 엔터를 입력하면 빠져 나감.
else strncat( bufpw, buffer, retval );
}
printf("패스워드를 입력받습니다 : %s\n", bufpw);
// 입력받은 패스워드 비교 부분
char *password = "mypass";
int password_size = (int)strlen(password);
int bufpw_size = (int)strlen(bufpw);
// 길이를 먼저 비교해보고 맞으면 길이만큼 패스워드 비교
// 패스워드가 맞으면 onoff = true 넣어주고, 틀리면 계속 진행
// printf("bufpw %d, password %d\n", bufpw_size, password_size);
if( !((bufpw_size == password_size) && (strncmp(bufpw, password, password_size) == 0)) ) continue;
else
{
onoff = true; // 서버를 시작하기 위해 true 값을 설정
break; // 패스워드 3회 체크 for문 탈출
}
} // for 패스워드 3회 비교 부분
// 서버 시작부분 if 문
if( onoff == true )
{
// 클라이언트측에 환영 메시지 표시
char *welcome = "\r\nWelcome to Telnet server!\r\n";
retval = send(clnt_sock, welcome, (int)strlen(welcome), 0);
if( retval == SOCKET_ERROR ) err_handler("send to client end of line()");
// bufpw 버퍼를 명령어 버퍼로 재활용합니다.
ZeroMemory( bufpw, sizeof(bufpw) );
while( TRUE )
{
// buffer 버퍼를 초기화합니다.(초기화하지 않으면 쓰레기값이 많음)
ZeroMemory( buffer, sizeof(buffer) );
// recv()
retval = recv( clnt_sock, buffer, BUFMAX, 0 );
if( retval == SOCKET_ERROR )
{
err_handler("recv()"); // 에러출력 함수에 recv() 전달
break;
}
else if(retval == 0) break; // (retval == 0 정상 소켓 종료)
buffer[retval] = '\0'; // ZeroMemory 해서 하지 않아도 되지만 정석으로 하는 과정임.
//------------------------------------------------------//
// 위의 패스워드 입력 버퍼 복사 부분처럼 //
// while 문으로 쓰지 않아도 아래 if 문장이 엔터 입력을 //
// 받지 않으면 루프 반복되어서 while문을 따로 쓰지 않음.//
//------------------------------------------------------//
// buffer를 bufpw(명령어버퍼)에 복사한다.
strncat( bufpw, buffer, retval );
printf("%s", buffer);
// ---------------------------------------------------------------- //
// 엔터가 입력되면 네트워크로 \r\n 패킷이 온다. //
// 엔터 패킷만 왔을때에는 buffer[0]='\r', buffer[1]='\n'이 된다. //
// ---------------------------------------------------------------- //
if( buffer[retval-1] == '\n' )
{
// 엔터명령을 받은후 명령어 출력
printf( "입력받은 명령어 : %s", bufpw );
// 명령어 해석 / 실행 / 결과 전송
if( strncmp(bufpw, "exit", 4) == 0)
{
strcat( buffer, "<exit 명령어 실행 완료>" ); // 메시지 설정
strcat( buffer, "\r\n" ); // 클라이언트로 보낼 버퍼에 완료 메시지
printf( "%s\n", buffer ); // 서버에 완료 메시지 출력
retval = (int)strlen( buffer ); // 메시지 사이즈에 버퍼 크기를 맞춘다.
closesocket( clnt_sock ); // 소켓을 닫는다.
break;
} // if (exit 명령)
else if( strncmp(bufpw, "netstat", 7) == 0)
{
ShellExecute( NULL, "open", "cmd.exe", "/c netstat -an > netstat.txt", "c:\\", SW_HIDE );
strcat( buffer, "<netstat 명령어 실행 완료>" ); // 메시지 설정
strcat( buffer, "\r\n" ); // 클라이언트로 보낼 버퍼에 완료 메시지
printf( "%s\n", buffer ); // 서버에 완료 메시지 출력
retval = (int)strlen(buffer); // 메시지 사이즈에 버퍼 크기를 맞춘다.
FILE *read_file = fopen( "c:\\netstat.txt", "r" );// 읽을 파일의 포인터 선언
Sleep(1000); // 1초간 딜레이를 두어서 파일이 생성되기를 기다린다.
// 파일이 생성되지 않았을때 클라이언트에 메시지 출력
if (read_file == NULL)
{
char *msg = "결과 파일이 생성에 실패하였습니다.\r\n다시 시도해 주십시오.\r\n";
retval = send(clnt_sock, msg, (int)strlen(msg), 0);
if(retval == SOCKET_ERROR)
{
err_handler("netstat()");
break;
}
}
// 파일이 생성되었을 경우에 파일 내용을 보냄
else
{
while( (fgets(file_buffer, BUFMAX, read_file) != 0) )
{
strcat( file_buffer, "\r" ); // 한 라인이 끝나고 줄바꿈 표시
retval = send( clnt_sock, file_buffer, (int)strlen(file_buffer), 0 );
if( retval == SOCKET_ERROR )
{
err_handler("netstat()");
break;
}
} // while (fgets)
} // if_else 문장(파일 유무에 따른 절차)
fclose(read_file);
} // else if (netstat 명령)
//--------------------------------------------------//
// 명령어 수행 후 명령어 버퍼 초기화 및 계속 진행 //
// while() 시작에 초기화를 하면 되지만, //
// 이해를 돕기위해 명령어 수행 후 바로 버퍼 초기화 //
//--------------------------------------------------//
ZeroMemory( bufpw, sizeof(bufpw) );
}
// send()
retval = send( clnt_sock, buffer, retval, 0 );
if( retval == SOCKET_ERROR )
{
err_handler("send()");
break;
}
} // while문 recv() send()
} // if onoff 서버 본문
printf( "%s:%d에서의 클라이언트 연결을 끊습니다.\n", inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port) );
closesocket( clnt_sock );
return 0;
}
덧글을 달아 주세요