본 내용은 <POCO를 이용한 C++ 네트워크 프로그래밍>을 읽고 내 머리속에 정리된 내용을 남겨본다.
POCO라이브러리는 boost::asio처럼 네트워크 라이브러리이다.
기존의 socket 프로그래밍을 할려면 초기화-bind-listen이라는 과정을 알아야 하는 데 이런 라이브러리를 사용하면 안에서 그러한 내부적인 처리를 다 하기 때문에 사용하는 입장에서는 구현에만 집중하면 된다.
일단 POCO는 멀티플랫폼을 지향하여 JAVA의 클래스라이브러리, .NET프레임워크 인터페이스를 지향하기 때문에 비슷한 부분이 많으며 코딩스타일이나 이런 것 역시 잘 지키기 때문에 코드 가독성이 좋다.
또한 무엇보다 오픈소스이기 때문에 상용/비상용에서 무료로 모두 사용할 수 있다.
기능적으로는 IOCP와 같은 기능은 제공해주지 않으며 HTTP서버와 클라이언트, TCP 서버 프레임워크(멀티스레드), FTP 클라이언트, 메일 전송을 위한 SMTP 클라이언트, 수신용 POP3 클라이언트를 제공한다.
Boost::asio에 지원하지 않는 부가적인 기능을 많이 제공해주므로 asio를 사용하더라도 보조적인 도구로 POCO를 사용하여도 좋다는 조언이 있다.
TCP에코서버와 클라이언트 예제를 보면서 POCO의 소개를 마쳐본다.
TCP에코 서버
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/SocketAddress.h"
const Poco::UInt16 PORT = 32452;
void main()
{
std::cout << "서버 초기화 시작" << std::endl;
Poco::Net::SocketAddress server_add(PORT);
Poco::Net::ServerSocket server_sock(server_add);
std::cout << "서버 초기화 완료. 클라이언트 접속 대기 중..." << std::endl;
while (true)
{
// 클라이언트로부터 접속 요청을 수락한다.
Poco::Net::StreamSocket ss = server_sock.acceptConnection();
try
{
char buffer[256] = { 0, };
int n = ss.receiveBytes(buffer, sizeof(buffer));
std::cout << "클라이언트에서 받은 메시지: " << buffer << std::endl;
while (n > 0)
{
char szSendMessage[256] = { 0, };
sprintf_s(szSendMessage, 256 - 1, "Re:%s", buffer);
int nMsgLen = strnlen_s(szSendMessage, 256 - 1);
ss.sendBytes(szSendMessage, sizeof(buffer));
n = ss.receiveBytes(buffer, sizeof(buffer));
std::cout << "클라이언트에서 받은 메시지: " << buffer << std::endl;
}
std::cout << "클라이언트와 연결이 끊어졌습니다." << std::endl;
}
catch (Poco::Exception& exc)
{
std::cout << "EchoServer: " << exc.displayText() << std::endl;
}
}
getchar();
}
|
cs |
TCP에코 클라이언트
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/SocketAddress.h"
const Poco::UInt16 PORT = 32452;
void main()
{
std::cout << "서버에 연결 시도..." << std::endl;
Poco::Net::StreamSocket ss;
try
{
ss.connect(Poco::Net::SocketAddress("localhost", PORT));
for (int i = 0; i < 7; ++i)
{
char szMessage[128] = { 0, };
sprintf_s(szMessage, 128 - 1, "%d - Send Message", i);
int nMsgLen = strnlen_s(szMessage, 128 - 1);
ss.sendBytes(szMessage, nMsgLen);
std::cout << "서버에 보낸 메시지: " << szMessage << std::endl;
char buffer[256] = { 0, };
auto len = ss.receiveBytes(buffer, sizeof(buffer));
if (len <= 0)
{
std::cout << "서버와 연결이 끊어졌습니다" << std::endl;
break;
}
std::cout << "서버로부터 받은 메시지: " << buffer << std::endl;
}
ss.close();
}
catch (Poco::Exception& exc)
{
std::cout << "서버 접속 실패" << exc.displayText() << std::endl;
}
getchar();
}
|
cs |
우리가 처음 배울 때 이런 프로그램을 만드는 데 그런 코드와 비교했을 때 상당히 짧고 가독성이 높아보이는게 POCO라이브러리의 장점이 아닐까한다.
이어서 UDP도 비교를 위해서 올려본다.
UDP 에코 클라이언트
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/DatagramSocket.h"
const Poco::UInt16 MY_PORT = 32451;
const Poco::UInt16 OTHER_PORT = 32452;
void main()
{
// UDP는 클라이언트와 서버가 연결된 상태가 아니므로 소켓 생성시 사용할 포트 번호를 설정해줘야 한다.
Poco::Net::DatagramSocket ss(MY_PORT);
try
{
for (int i = 0; i < 7; ++i)
{
char szMessage[128] = { 0, };
sprintf_s(szMessage, 128 - 1, "%d - Send Message", i);
int nMsgLen = strnlen_s(szMessage, 128 - 1);
// 서버에 데이터를 보낼 함수를 호출할 때마다 데이터 받을 곳의 주소를 지정한다.
// Poco::Net::SocketAddress("localhost", OTHER_PORT)
ss.sendTo(szMessage, nMsgLen, Poco::Net::SocketAddress("localhost", OTHER_PORT));
std::cout << "서버에 보낸 메시지: " << szMessage << std::endl;
char buffer[256] = { 0, };
// 서버와 연결된 상태가 아니므로 해당 받은 데이터가 어디로부터 왔는지를 알기 위해 세번째 인자인
// sender를 넘겨준다.
// 그러면 이 sender에 설정된 정보를 통해서 어디서 왔는지를 알 수 있다.
Poco::Net::SocketAddress sender;
auto len = ss.receiveFrom(buffer, sizeof(buffer), sender);
if (len <= 0)
{
std::cout << "서버와 연결이 끊어졌습니다" << std::endl;
break;
}
std::cout << "서버로부터 받은 메시지: " << buffer << std::endl;
}
ss.close();
}
catch (Poco::Exception& exc)
{
std::cout << "서버 접속 실패" << exc.displayText() << std::endl;
}
getchar();
}
|
cs |
UDP 에코 서버i
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Net/SocketAddress.h"
const Poco::UInt16 MY_PORT = 32452;
void main()
{
Poco::Net::DatagramSocket serv_sock(MY_PORT);
Poco::Net::SocketAddress client;
while (true)
{
try
{
char buffer[256] = { 0, };
Poco::Net::SocketAddress sender;
int len = serv_sock.receiveFrom(buffer, sizeof(buffer), sender);
if (len > 0)
{
std::cout << buffer << " from " << sender.host().toString() << ":" << sender.port() << std::endl;
char szSendMessage[256] = { 0, };
sprintf_s(szSendMessage, 256 - 1, "Re:%s", buffer);
int nMsgLen = strnlen_s(szSendMessage, 256 - 1);
serv_sock.sendTo(szSendMessage, sizeof(buffer), sender);
}
}
catch (Poco::Exception& exc)
{
std::cout << "EchoServer: " << exc.displayText() << std::endl;
}
}
getchar();
}
|
cs |

