当前位置:首页 > > 充电吧
[导读]       回显就是服务端将接收到的任何内容回发给客户端显示,然后关闭客户端的连接。这个服务端可以处理任何数量的客户端。每个客户端连接之后发送一个消息,服务端接收到消息后把它发送回去。在那之后,服务

       回显就是服务端将接收到的任何内容回发给客户端显示,然后关闭客户端的连接。这个服务端可以处理任何数量的客户端。每个客户端连接之后发送一个消息,服务端接收到消息后把它发送回去。在那之后,服务端关闭连接。具体流程如下图所示。


       对于TCP而言,我们需要一个额外的保证:每一个消息以换行符结束(‘n’)。编写一个同步回显服务端/客户端非常简单。下面我们分别实现同步客户端,同步服务端,异步客户端和异步服务端。

一.TCP同步客户端

#ifdef WIN32
#define _WIN32_WINNT 0x0501
#include#endif

#include#include#include#include#includeusing namespace boost::asio;
using boost::system::error_code;
io_service service;

size_t read_complete(char * buf, const error_code & err, size_t bytes) {
	if (err) return 0;
	bool found = std::find(buf, buf + bytes, 'n') < buf + bytes;
	// 一个一个字符的读取,直到回车, 不缓存
	return found ? 0 : 1;
}

ip::tcp::endpoint ep(ip::address::from_string("127.0.0.1"), 8001);
void sync_echo(std::string msg) {
	msg += "n";
	ip::tcp::socket sock(service);
	sock.connect(ep);
	sock.write_some(buffer(msg));
	char buf[1024];
	int bytes = read(sock, buffer(buf), boost::bind(read_complete, buf, _1, _2));
	std::string copy(buf, bytes - 1);
	msg = msg.substr(0, msg.size() - 1);
	std::cout << "server echoed our " << msg << ": "
		<< (copy == msg ? "OK" : "FAIL") << std::endl;
	sock.close();
}

int main(int argc, char* argv[]) {
	// 连接多个客户端
	char* messages[] = { "Can", "ge", "ge", "blog!", 0 };
	boost::thread_group threads;
	for (char ** message = messages; *message; ++message) {
		threads.create_thread(boost::bind(sync_echo, *message));
		boost::this_thread::sleep(boost::posix_time::millisec(100));
	}
	threads.join_all();

	system("pause");
}

       你会发现,在读取时,我使用了自由函数(不属于socket类,属于命名空间asio)read(),因为我想要读‘n’之前的所有内容。sock.read_some()方法满足不了这个要求,因为它只会读可用的,不一定是整个的消息。
       read(stream, buffer [, completion])这个方法同步地从一个流中读取数据。你可以选择指定一个完成处理方法。完成处理方法会在每次read操作调用成功之后调用,然后告诉read操作是否完成(如果没有完成,它会继续读取)。它的格式是:size_t completion(const boost::system::error_code& err, size_t bytes_transfered) 。当这个完成处理方法返回0时,我们认为read操作完成;如果它返回一个非0值,它表示了下一次sock.read_some操作需要从流中读取的字节数。

       read_complete一个个的读取字符,直到回车,这是通过std::find方法控制的,std::find的行为大概如下。

templateInputIterator find (InputIterator first, InputIterator last, const T& val)
{
  while (first!=last) {
    if (*first==val) return first;
    ++first;
  }
  return last;
}

       结合到上面客户端代码就是,如果没有找到回车'n',std::find始终返回buf+bytes,否则返回'n'的地址,也就是buf+bytes-1,此时'n'是已读取内容的最后一个字符。
       注意:因为我们是同步的,所以不需要调用service.run()。

二.TCP同步服务端

#ifdef WIN32
#define _WIN32_WINNT 0x0501
#include#endif

#include#include#include#includeusing namespace boost::asio;
using namespace boost::posix_time;
using boost::system::error_code;


io_service service;
size_t read_complete(char * buff, const error_code & err, size_t bytes) {
    if ( err) return 0;
    bool found = std::find(buff, buff + bytes, 'n') < buff + bytes;
    // we read one-by-one until we get to enter, no buffering
    return found ? 0 : 1;
}


void handle_connections() {
    ip::tcp::acceptor acceptor(service, ip::tcp::endpoint(ip::tcp::v4(),8001));
    char buff[1024];
    while ( true) {
        ip::tcp::socket sock(service);
        acceptor.accept(sock);
        int bytes = read(sock, buffer(buff), 
                    boost::bind(read_complete,buff,_1,_2));
        std::string msg(buff, bytes);
        sock.write_some(buffer(msg));
        sock.close();
    }
}


int main(int argc, char* argv[]) {
    handle_connections();
}

       服务端的逻辑主要在handle_connections()。因为是单线程,它接受一个客户端请求,读取客户端发送的消息,然后回发给客户端,接着等待下一个连接。可以确定,当两个客户端同时连接时,第二个客户端需要等待服务端处理完第一个客户端的请求。

       还是要注意因为我们是同步的,所以不需要调用service.run()。

       下面是客户端回显的结果,当然要先启动服务端。


三.TCP异步客户端

#ifdef WIN32
#define _WIN32_WINNT 0x0501
#include#endif

#include#include#include#include#includeusing namespace boost::asio;
io_service service;

#define MEM_FN(x)       boost::bind(&self_type::x, shared_from_this())
#define MEM_FN1(x,y)    boost::bind(&self_type::x, shared_from_this(),y)
#define MEM_FN2(x,y,z)  boost::bind(&self_type::x, shared_from_this(),y,z)

class talk_to_svr : public boost::enable_shared_from_this
	, boost::noncopyable {
	typedef talk_to_svr self_type;
	talk_to_svr(const std::string & message)
		: sock_(service), started_(true), message_(message) {}
	void start(ip::tcp::endpoint ep) {
		sock_.async_connect(ep, MEM_FN1(on_connect, _1));
	}
public:
	typedef boost::system::error_code error_code;
	typedef boost::shared_ptrptr;

	static ptr start(ip::tcp::endpoint ep, const std::string & message) {
		ptr new_(new talk_to_svr(message));
		new_->start(ep);
		return new_;
	}
	void stop() {
		if (!started_) return;
		started_ = false;
		sock_.close();
	}
	bool started() { return started_; }
private:
	void on_connect(const error_code & err) {
		if (!err)      do_write(message_ + "n");
		else            stop();
	}
	void on_read(const error_code & err, size_t bytes) {
		if (!err) {
			std::string copy(read_buffer_, bytes - 1);
			std::cout << "server echoed our " << message_ << ": "
				<< (copy == message_ ? "OK" : "FAIL") << std::endl;
		}
		stop();
	}

	void on_write(const error_code & err, size_t bytes) {
		do_read();
	}
	void do_read() {
		async_read(sock_, buffer(read_buffer_),
			MEM_FN2(read_complete, _1, _2), MEM_FN2(on_read, _1, _2));
	}
	void do_write(const std::string & msg) {
		if (!started()) return;
		std::copy(msg.begin(), msg.end(), write_buffer_);
		sock_.async_write_some(buffer(write_buffer_, msg.size()),
			MEM_FN2(on_write, _1, _2));
	}
	size_t read_complete(const boost::system::error_code & err, size_t bytes) {
		if (err) return 0;
		bool found = std::find(read_buffer_, read_buffer_ + bytes, 'n') < read_buffer_ + bytes;
		return found ? 0 : 1;
	}

private:
	ip::tcp::socket sock_;
	enum { max_msg = 1024 };
	char read_buffer_[max_msg];
	char write_buffer_[max_msg];
	bool started_;
	std::string message_;
};

int main(int argc, char* argv[]) {
	ip::tcp::endpoint ep(ip::address::from_string("127.0.0.1"), 8001);
	char* messages[] = { "Can", "ge", "ge", "blog", 0 };
	for (char ** message = messages; *message; ++message) {
		talk_to_svr::start(ep, *message);
		boost::this_thread::sleep(boost::posix_time::millisec(100));
	}
	service.run();
	system("pause");
}

四.TCP异步服务端

#ifdef WIN32
#define _WIN32_WINNT 0x0501
#include#endif

#include#include#include#includeusing namespace boost::asio;
using namespace boost::posix_time;
io_service service;

#define MEM_FN(x)       boost::bind(&self_type::x, shared_from_this())
#define MEM_FN1(x,y)    boost::bind(&self_type::x, shared_from_this(),y)
#define MEM_FN2(x,y,z)  boost::bind(&self_type::x, shared_from_this(),y,z)


class talk_to_client : public boost::enable_shared_from_this, boost::noncopyable {
	typedef talk_to_client self_type;
	talk_to_client() : sock_(service), started_(false) {}
public:
	typedef boost::system::error_code error_code;
	typedef boost::shared_ptrptr;

	void start() {
		started_ = true;
		do_read();
	}
	static ptr new_() {
		ptr new_(new talk_to_client);
		return new_;
	}
	void stop() {
		if (!started_) return;
		started_ = false;
		sock_.close();
	}
	ip::tcp::socket & sock() { return sock_; }
private:
	void on_read(const error_code & err, size_t bytes) {
		if (!err) {
			std::string msg(read_buffer_, bytes);
			// echo message back, and then stop
			do_write(msg + "n");
		}
		stop();
	}

	void on_write(const error_code & err, size_t bytes) {
		do_read();
	}
	void do_read() {
		async_read(sock_, buffer(read_buffer_),
			MEM_FN2(read_complete, _1, _2), MEM_FN2(on_read, _1, _2));
	}
	void do_write(const std::string & msg) {
		std::copy(msg.begin(), msg.end(), write_buffer_);
		sock_.async_write_some(buffer(write_buffer_, msg.size()),
			MEM_FN2(on_write, _1, _2));
	}
	size_t read_complete(const boost::system::error_code & err, size_t bytes) {
		if (err) return 0;
		bool found = std::find(read_buffer_, read_buffer_ + bytes, 'n') < read_buffer_ + bytes;
		// we read one-by-one until we get to enter, no buffering
		return found ? 0 : 1;
	}
private:
	ip::tcp::socket sock_;
	enum { max_msg = 1024 };
	char read_buffer_[max_msg];
	char write_buffer_[max_msg];
	bool started_;
};

ip::tcp::acceptor acceptor(service, ip::tcp::endpoint(ip::tcp::v4(), 8001));

void handle_accept(talk_to_client::ptr client, const boost::system::error_code & err) {
	client->start();
	talk_to_client::ptr new_client = talk_to_client::new_();
	acceptor.async_accept(new_client->sock(), boost::bind(handle_accept, new_client, _1));
}


int main(int argc, char* argv[]) {
	talk_to_client::ptr client = talk_to_client::new_();
	acceptor.async_accept(client->sock(), boost::bind(handle_accept, client, _1));
	service.run();
}

      TCP异步客户端和异步服务端的关键是enable_shared_from_this模板类的使用,关于enable_shared_from_this详见:C++11新特性之十一:enable_shared_from_this,C++11和boost的enable_shared_from_this功能和原理一样。

       客户端回显结果和同步时的一样,如下:





本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭