sw2007/03/21 17:43
Introduction
윈속api는 마이크로소프트 윈도우 운영체제를 위한 소켓 프로그래밍 라이브러리이다.

윈속은 버클리소켓을 기반으로 만들어졌다.

그렇지만 대부분 마이크로소프트는 채용하면서 형태를 바꾼다.

이 기사에서 나는 소개하기위해 시도할 것이다. 당신이 어떤한 운영체제에서도 네트워크 프로그래밍 같은 것을 해본적이 없다는 가정하에 WinSock을 이용하여 소켓프로그래밍을 할 수 있게 할 것이다.

컴퓨터가 한대밖에 없다고 해서 걱정할 일도 없다. WinSock 프로그램은 로컬 루프 백 주소인 127.0.0.1을 호출하여 할 수 있다.

그러므로 만약 당신이 TCP 서버를 돌리는 당신의 컴퓨터에서 돌린다 해도, 클라이언트 프로그램은 동일한 컴퓨터에서 서버에 연결할수 있다.

Simple TCP Server
이 기사에서 WinSock을 이용한 차례차례 만들어갈수 있는 간단한 TCP 서버를 소개할 것이다.

시작하기전에 몇가지 해야할 것이 있다. WinSock 프로그램을 시작하기전에 해야할 것들이다.

Win32 콘솔 어플리케이션을 VC++6.0 어플리케이션 위저드를 이용하여 만든다.
MFC를 지원하는 옵션을 선택하는것을 기억해야 한다.
#include 를 stdafx.h에 추가해야 한다.
winsock2.h 다음에는 #include conio.h와 iostream.h도 해주어야 한다.
Project-Settings-Link에서 ws2_32.lib 를 library modules 리스트에 적어준다.

The main function

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
cout < < "Press ESCAPE to terminate program\r\n";
AfxBeginThread(ServerThread,0);
while(_getch()!=27);
return nRetCode;
}

main() 에서 하는 것은 Thread를 시작하고, 루프를 돌며 _getch() 함수를 호출한다.
_getch()는 단순히 키가 눌리기 전이나, 반환한 아스키 값을 받을때 까지 기다린다.

ESCAPE 키의 아스키 코드 값인 27의 값이 리턴되기 전까지 루프를 돈다.

ESCAPE을 누르는 것을 쓰레드가 시작되어서 아직 활성화 되어있기 때문에 항상 고려해야 한다.

그런 모든것들에 대해 걱정하지 마라.

main()이 리턴할때는 프로세스는 종료되었거나 쓰레드가 시작되었는데 주 쓰레드가 갑자기 종료되는 경우이다.

The ServerThread function

내가 지금 하려는 것은 서버 쓰레드 함수의 나열과 사용한 코드의 설명을 하기 위한 주석이다. 각 라인의 코드들에 대한 설명이다.

기본적으로 우리의 TCP 서버는 이와 같은 것을 해야 한다.

20248 포트에서 나의 코드 프로젝트 멤버쉽 아이디 입력하는 것을 listen 한다.

동시에 Talk 한다.

클라이언트가 접속했을때, 서버는 메세지를 돌려 보내고 클라이언트에게 줄 IP 주소와 연결을 닫고 연결 수락을 돌려 보낼때
20248포트로 보낼것이다.

실행하며 특정 IP주소로 부터 연결을 해서 콘솔에 한줄을 찍을 것이다.

쓸모없는 프로그램이라고 생각될 것이다.

사실 몇몇 어떤 이들은 할것이다 종종 생각을 이 필요없는 SNDREC32.EXE 윈도우에서는

터무니 없이 그들에게 말한다.

UINT ServerThread(LPVOID pParam)
{
cout << "Starting up TCP server\r\n";
//A SOCKET is simply a typedef for an unsigned int.
//In Unix, socket handles were just about same as file
//handles which were again unsigned ints.
//Since this cannot be entirely true under Windows
//a new data type called SOCKET was defined.

SOCKET server;

//WSADATA is a struct that is filled up by the call
//to WSAStartup

WSADATA wsaData;

//The sockaddr_in specifies the address of the socket
//for TCP/IP sockets. Other protocols use similar structures.

sockaddr_in local;

//WSAStartup initializes the program for calling WinSock.
//The first parameter specifies the highest version of the
//WinSock specification, the program is allowed to use.

int wsaret=WSAStartup(0x101,&wsaData);

//WSAStartup returns zero on success.
//If it fails we exit.

if(wsaret!=0){ return 0;
}

//Now we populate the sockaddr_in structure

local.sin_family=AF_INET;

//Address family

local.sin_addr.s_addr=INADDR_ANY;

//Wild card IP address

local.sin_port=htons((u_short)20248);

//port to use
//the socket function creates our

SOCKET server=socket(AF_INET,SOCK_STREAM,0);

//If the socket() function fails we exit

if(server==INVALID_SOCKET)
{
return 0;
}

//bind links the socket we just created with the sockaddr_in
//structure. Basically it connects the socket with
//the local address and a specified port.
//If it returns non-zero quit, as this indicates error

if(bind(server,(sockaddr*)&local,sizeof(local))!=0)
{
return 0;
}

//listen instructs the socket to listen for incoming
//connections from clients. The second arg is the backlog

if(listen(server,10)!=0)
{
return 0;
}
//we will need variables to hold the client socket.
//thus we declare them here.

SOCKET client;
sockaddr_in from;
int fromlen=sizeof(from);
while(true)
//we are looping endlessly

{
char temp[512];

//accept() will accept an incoming
//client connection

client=accept(server, (struct sockaddr*)&from,&fromlen);
sprintf(temp,"Your IP is %s\r\n",inet_ntoa(from.sin_addr));

//we simply send this string to the client

send(client,temp,strlen(temp),0);
cout << "Connection from " << inet_ntoa(from.sin_addr) <<"\r\n";

//close the client socket

closesocket(client);
}

//closesocket() closes the socket and releases the socket descriptor

closesocket(server);

//originally this function probably had some use
//currently this is just for backward compatibility
//but it is safer to call it as I still believe some
//implementations use this to terminate use of WS2_32.DLL

WSACleanup();
return 0;
}

Testing it out
서버가구동되고 사용자가 텔넷을 사용하여 실행중인 서버의 20248포트로 접속한다.

동일 컴퓨터에서 접속한다면 localhost로 접속한다.

Sample Output
서버에서 아래와 같은 출력화면을 볼수 있을것이다.

E:\work\Server\Debug>server
Press ESCAPE to terminate program Starting up TCP server Connection from 203.200.100.122 Connection from 127.0.0.1
E:\work\Server\Debug>
그리고 클라이언트에서 얻은 정보이다.

nish@sumida:~$ telnet 202.89.211.88 20248 Trying 202.89.211.88… Connected to 202.89.211.88. Escape character is ‘^]’. Your IP is 203.200.100.122 Connection closed by foreign host. nish@sumida:~$
Conclusion

간단한 TCP서버를 만들어 보았다.
Posted by redef

댓글을 달아 주세요