代码:
//
// UserTcpServer.cpp
//
// This sample demonstrates the SocketReactor and SocketAcceptor classes.
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stddef.h>
#include <iostream>
#include "Poco/Net/SocketReactor.h"
#include "Poco/Net/SocketAcceptor.h"
#include "Poco/Net/SocketNotification.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/NObserver.h"
#include "Poco/Exception.h"
#include "Poco/Thread.h"
#include "Poco/FIFOBuffer.h"
#include "Poco/Delegate.h"
#include "Poco/Util/ServerApplication.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/Util/HelpFormatter.h"
#include "Poco/LocalDateTime.h"
#include "Poco/DateTime.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeParser.h"
class UserServiceHandler
{
public:
UserServiceHandler(Poco::Net::StreamSocket& socket, Poco::Net::SocketReactor& reactor):
socket_(socket), reactor_(reactor)
{
Poco::Util::Application& app = Poco::Util::Application::instance();
app.logger().information("Connection from " + socket.peerAddress().toString());
recv_buf_ = (uint8_t *)malloc(BUFFER_SIZE);
send_buf_ = (uint8_t *)malloc(BUFFER_SIZE);
recv_len_ = 0;
send_len_ = 0;
reactor_.addEventHandler(socket_, Poco::NObserver<UserServiceHandler, Poco::Net::ReadableNotification>(*this, &UserServiceHandler::onSocketReadable));
reactor_.addEventHandler(socket_, Poco::NObserver<UserServiceHandler, Poco::Net::ShutdownNotification>(*this, &UserServiceHandler::onSocketShutdown));
}
~UserServiceHandler()
{
Poco::Util::Application& app = Poco::Util::Application::instance();
try
{
app.logger().information("Disconnecting " + socket_.peerAddress().toString());
}
catch (...)
{
}
reactor_.removeEventHandler(socket_, Poco::NObserver<UserServiceHandler, Poco::Net::ReadableNotification>(*this, &UserServiceHandler::onSocketReadable));
reactor_.removeEventHandler(socket_, Poco::NObserver<UserServiceHandler, Poco::Net::WritableNotification>(*this, &UserServiceHandler::onSocketWritable));
reactor_.removeEventHandler(socket_, Poco::NObserver<UserServiceHandler, Poco::Net::ShutdownNotification>(*this, &UserServiceHandler::onSocketShutdown));
if (recv_buf_)
{
free(recv_buf_);
recv_buf_ = NULL;
}
if (send_buf_)
{
free(send_buf_);
send_buf_ = NULL;
}
}
void onSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf)
{
recv_len_ = socket_.receiveBytes(recv_buf_, BUFFER_SIZE);
if (recv_len_ > 0)
{
// do some user work here
// do some user work here
// do some user work here
// sleep(1); // 不要sleep,不要花时间处理数据,先把数据拷贝到链表里,放其他线程单独处理数据。
// example
// receive string
// return server date
printf("RECV - %s\n\r", recv_buf_);
Poco::LocalDateTime now;
std::string time_str = Poco::DateTimeFormatter::format(now, Poco::DateTimeFormat::ISO8601_FRAC_FORMAT);
//
send_len_ = sprintf((char *)send_buf_, "%s, SVR - %s\n\r", recv_buf_, time_str.c_str());
send_buf_[send_len_ ++] = '\0';
// en send
reactor_.addEventHandler(socket_, Poco::NObserver<UserServiceHandler, Poco::Net::WritableNotification>(*this, &UserServiceHandler::onSocketWritable));
}
}
void onSocketWritable(const Poco::AutoPtr<Poco::Net::WritableNotification>& pNf)
{
if (send_len_ > 0)
{
socket_.sendBytes(send_buf_, send_len_);
}
//
reactor_.removeEventHandler(socket_, Poco::NObserver<UserServiceHandler, Poco::Net::WritableNotification>(*this, &UserServiceHandler::onSocketWritable));
}
void onSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf)
{
delete this;
}
private:
enum
{
BUFFER_SIZE = 1024
};
Poco::Net::StreamSocket socket_;
Poco::Net::SocketReactor& reactor_;
uint8_t *recv_buf_; // 接收缓存区
uint8_t *send_buf_; // 发送缓存区
int recv_len_;
int send_len_;
};
class UserTcpServer: public Poco::Util::ServerApplication
{
public:
UserTcpServer(Poco::Net::SocketAddress &socket_addr)
{
socket_addr_ = &socket_addr;
}
~UserTcpServer()
{
}
protected:
void initialize(Application& self)
{
Poco::Util::ServerApplication::initialize(self);
}
void uninitialize()
{
Poco::Util::ServerApplication::uninitialize();
}
int main(const std::vector<std::string>& args)
{
// set-up a server socket
Poco::Net::ServerSocket svs(*socket_addr_);
// set-up a SocketReactor...
Poco::Net::SocketReactor reactor;
// ... and a SocketAcceptor
Poco::Net::SocketAcceptor<UserServiceHandler> acceptor(svs, reactor);
// run the reactor in its own thread so that we can wait for
// a termination request
Poco::Thread thread;
thread.start(reactor);
// wait for CTRL-C or kill
Poco::Util::ServerApplication::waitForTerminationRequest();
// Stop the SocketReactor
reactor.stop();
thread.join();
return Poco::Util::Application::EXIT_OK;
}
private:
Poco::Net::SocketAddress *socket_addr_;
};
int main(int argc, char** argv)
{
int server_port = 8089;
std::string server_ip("localhost");
Poco::Net::SocketAddress socket_addr(server_ip.c_str(), server_port);
UserTcpServer app(socket_addr);
return app.run(argc, argv);
}
makefile:
export TOP_DIR = $(PWD)
# 包含参数配置文件
#include ./Makefile.param
# 目标文件名称、编译后文件位置
PWD := $(shell pwd)
INSTALLDIR = .
TARGET = tcp_server_test
DBGTARGET = $(INSTALLDIR)/$(TARGET)d
RLSTARGET = $(INSTALLDIR)/$(TARGET)
# 配置编译器
CC = $(CROSS_COMPILE)gcc
CXX = $(CROSS_COMPILE)g++
LD_CXX = $(CROSS_COMPILE)g++
STRIP = $(CROSS_COMPILE)strip
RM = rm
# 配置依赖头文件、库文件路径
INCPATH += -I. -I$(REL_INC) -I/usr/local/include
LIBPATH += -L. -L$(REL_LIB) -L/usr/local/lib
# 配置编译参数
FLAGS_C += $(MACRO_DEFINE) $(INCPATH) $(CFLAGS) -Wall
FLAGS_CXX += $(MACRO_DEFINE) $(INCPATH) $(CFLAGS) -Wall
LDFLAGS += $(CFLAGS) $(LIBPATH) $(LIBS_CFLAGS) -pie -fPIE
LIBS += -lPocoFoundation -lPocoUtil -lPocoNet -lpthread -lm -lc -lgcc -lgcc_s -ldl
DBG_FLAGS = -g -D__DEBUG
RLS_FLAGS = -O2 -fno-strict-aliasing
# 源文件包含
SRCS_C = $(wildcard *.c)
SRCS_CXX = $(wildcard *.cpp)
SRCS_H = $(wildcard *.h*)
# obj文件包含
OBJ_DBG_DIR = 0-obj/$(CROSS_COMPILE)dbg
OBJ_RLS_DIR = 0-obj/$(CROSS_COMPILE)rls
OBJS_C_DBG = $(addprefix $(OBJ_DBG_DIR)/,$(SRCS_C:%.c=%.o))
OBJS_CXX_DBG = $(addprefix $(OBJ_DBG_DIR)/,$(SRCS_CXX:%.cpp=%.o))
OBJS_C_RLS = $(addprefix $(OBJ_RLS_DIR)/,$(SRCS_C:%.c=%.o))
OBJS_CXX_RLS = $(addprefix $(OBJ_RLS_DIR)/,$(SRCS_CXX:%.cpp=%.o))
# 编译动作
COMPILE_C = $(CC) $(FLAGS_C) -c
COMPILE_CXX = $(CXX) $(FLAGS_CXX) -c
LINK_CXX = $(LD_CXX) $(LDFLAGS)
.PHONY: clean debug release install
all: release
install:
install -d $(EXEC_DIR)
install $(RLSTARGET) $(EXEC_DIR)
install -m 444 $(TARGET).txt $(EXEC_DIR)
release: $(RLSTARGET)
$(STRIP) $(RLSTARGET)
debug: $(DBGTARGET)
@echo $(TARGET)_debug_done
$(RLSTARGET): $(OBJS_C_RLS) $(OBJS_CXX_RLS)
@mkdir -p $(INSTALLDIR)
$(LINK_CXX) -o $@ $^ $(LIBS)
$(DBGTARGET): $(OBJS_C_DBG) $(OBJS_CXX_DBG)
@mkdir -p $(INSTALLDIR)
$(LINK_CXX) -o $@ $^ $(LIBS)
$(OBJS_CXX_RLS): $(OBJ_RLS_DIR)/%.o: %.cpp $(SRCS_H)
@mkdir -p $(OBJ_RLS_DIR)
$(COMPILE_CXX) $(RLS_FLAGS) -o $@ $<
$(OBJS_C_RLS): $(OBJ_RLS_DIR)/%.o: %.c $(SRCS_H)
@mkdir -p $(OBJ_RLS_DIR)
$(COMPILE_C) $(RLS_FLAGS) -o $@ $<
$(OBJS_CXX_DBG): $(OBJ_DBG_DIR)/%.o: %.cpp $(SRCS_H)
@mkdir -p $(OBJ_DBG_DIR)
$(COMPILE_CXX) $(DBG_FLAGS) -o $@ $<
$(OBJS_C_DBG): $(OBJ_DBG_DIR)/%.o: %.c $(SRCS_H)
@mkdir -p $(OBJ_DBG_DIR)
$(COMPILE_C) $(DBG_FLAGS) -o $@ $<
clean:
-$(RM) -rf *~ *.d .dep 0-obj