sync_func( arg1, arg2 ... argN); // 抛出异常
boost::system::error_code ec;
sync_func( arg1 arg2, ..., argN, ec); // 返回错误码
在这一章剩下的部分,你会见到大量的同步函数。简单起见,我省略了返回错误码的重载,但是它们是存在的。
套接字成员函数
这些函数被分成了几组。在各个类型的套接字里并不是所有的函数都可用。这个部分的结尾将有一个列表来展示哪个函数是属于哪个socket类的。
注意所有的异步函数都立刻返回,而它们相对的同步实现需要操作完成之后才能返回。
连接相关的函数
这些是连接或绑定套接字、断开套接字连接以及查询连接是活动还是非活动的函数:
assign(protocol,socket):这个函数分配了一个原生的套接字给这个套接字实例。当处理老(旧)程序时使用它(也就是说,原生套接字已经被建立了)
open(protocol):这个函数用给定的IP协议(v4或者v6)打开一个套接字。你主要在UDP/ICMP套接字,或者服务端套接字上使用。
bind(endpoint):这个函数绑定到一个地址
connect(endpoint):这个函数用同步的方式连接到一个地址
async_connect(endpoint):这个函数用异步的方式连接到一个地址
is_open():如果套接字已经打开,这个函数返回true
close():这个函数关闭套接字。这个套接字上任何的异步操作都会被立即关闭,同时返回error::operation_aborted错误码
shutdown(type_of_shutdown):这个函数立即使send或者receive操作失效,或者两者都失效。
cancel():这个函数取消这个套接字上所有的异步操作。这个套接字上任何的异步操作都会立即结束,然后返回error::operation_aborted错误码。
例子如下:
ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 80);
ip::tcp::socket sock(service);
sock.open(ip::tcp::v4()); n
sock.connect(ep);
sock.write_some(buffer("GET /index.html\r\n"));
char buff[1024]; sock.read_some(buffer(buff,1024));
sock.shutdown(ip::tcp::socket::shutdown_receive);
sock.close();
读写函数
这些是在套接字上执行I/O操作的函数
对于异步函数来说,处理程序的签名void handler(const boost::system::error_code& e, size_t bytes)都是一样的
async_receive(buffer, [flags,] handler):这个函数启动从套接字异步receive数据的操作。
async_read_some(buffer,handler):这个函数和async_receive(buffer, handler)功能一样。
async_receive_from(buffer, endpoint[, flags], handler):这个函数启动从一个指定端点异步receive数据的操作。
async_send(buffer [, flags], handler):这个函数启动了一个异步send缓冲区数据的功能。
async_write_some(buffer, handler):这个函数和async_send(buffer, handler)功能一致。
async_send_to(buffer, endpoint, handler):这个函数启动了一个异步send缓冲区数据到指定端点的功能。
receive(buffer [, flags]):这个函数异步地从所给的缓冲区读取数据。在读完所有数据或者错误出现之前,这个函数都是阻塞的。
read_some(buffer):这个函数的功能和receive(buffer)是一致的。
receive_from(buffer, endpoint [, flags]):这个函数异步地从一个指定的端点获取数据并写入到给定的缓冲区。在读完所有数据或者错误出现之前,这个函数都是阻塞的。
send(buffer [, flags]):这个函数同步地发送缓冲区的数据。在所有数据发送成功或者出现错误之前,这个函数都是阻塞的。
write_some(buffer):这个函数和send(buffer)的功能一致。
send_to(buffer, endpoint [, flags]):这个函数同步地把缓冲区数据发送到一个指定的端点。在所有数据发送成功或者出现错误之前,这个函数都是阻塞的。
available():这个函数返回有多少字节的数据可以无阻塞地进行同步读取。
稍后我们将讨论缓冲区。让我们先来了解一下标记。标记的默认值是0,但是也可以是以下几种:
ip::socket_type::socket::message_peek:这个标记只监测消息。它会返回这个消息,但是下一次读消息的调用会重新读取这个消息。
ip::socket_type::socket::message_out_of_band:这个标记处理带外(OOB)数据,OOB数据是被标记为比正常数据更重要的数据。关于OOB的讨论在这本书的内容之外。
ip::socket_type::socket::message_do_not_route:这个标记指定数据不使用路由表来发送。
ip::socket_type::socket::message_end_of_record:这个标记指定的数据标识了记录的结束。在Windows下不支持。
你最有可能使用message_peek,如果使用请参照下面的代码片段:
char buff[1024];
sock.receive(buffer(buff), ip::tcp::socket::message_peek );
memset(buff,1024, 0);
// re-reads what was previously read
sock.receive(buffer(buff) );
下面的是一些告诉你如何同步或异步地从不同类型的套接字读取数据的例子:
例子1是对一个TCP套接字进行同步的读写:
ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 80);
ip::tcp::socket sock(service);
sock.connect(ep);
sock.write_some(buffer("GET /index.html\r\n"));
std::cout << "bytes available " << sock.available() << std::endl;
char buff[512];
size_t read = sock.read_some(buffer(buff));
例子2是读一个UDP套接字进行同步的读写:
ip::udp::socket sock(service);
sock.open(ip::udp::v4());
ip::udp::endpoint receiver_ep("87.248.112.181", 80);
sock.send_to(buffer("testing\n"), receiver_ep);
char buff[512];
ip::udp::endpoint sender_ep;
sock.receive_from(buffer(buff), sender_ep);
[?注意:像上面代码片段展示的那样,使用receive_from从一个UDP套接字读取时,你需要一个默认构造的端点]
例子3是从一个UDP服务套接字中异步读取数据:
using namespace boost::asio;
io_service service;
ip::udp::socket sock(service);
boost::asio::ip::udp::endpoint sender_ep;
char buff[512];
void on_read(const boost::system::error_code & err, std::size_t
read_bytes) {
std::cout << "read " << read_bytes << std::endl;
sock.async_receive_from(buffer(buff), sender_ep, on_read);
}
int main(int argc, char* argv[]) {
ip::udp::endpoint ep( ip::address::from_string("127.0.0.1"),
8001);
sock.open(ep.protocol());
sock.set_option(boost::asio::ip::udp::socket::reuse_
address(true));
sock.bind(ep);
sock.async_receive_from(buffer(buff,512), sender_ep, on_read);
service.run();
}
套接字控制:
这些函数用来处理套接字的高级选项:
get_io_service():这个函数返回构造函数中传入的io_service实例
get_option(option):这个函数返回一个套接字的属性
set_option(option):这个函数设置一个套接字的属性
io_control(cmd):这个函数在套接字上执行一个I/O指令
这些是你可以获取/设置的套接字选项:
名字 描述 类型
broadcast 如果为true,允许广播消息 bool
debug 如果为true,启用套接字级别的调试 bool
do_not_route 如果为true,则阻止路由选择只使用本地接口 bool
enable_connection_aborted 如果为true,记录在accept()时中断的连接 bool
keep_alive 如果为true,会发送心跳 bool
linger 如果为true,套接字会在有未发送数据的情况下挂起close() bool
receive_buffer_size 套接字接收缓冲区大小 int
receive_low_watemark 规定套接字输入处理的最小字节数 int
reuse_address 如果为true,套接字能绑定到一个已用的地址 bool
send_buffer_size 套接字发送缓冲区大小 int
send_low_watermark 规定套接字数据发送的最小字节数 int
ip::v6_only 如果为true,则只允许IPv6的连接 bool
每个名字代表了一个内部套接字typedef或者类。下面是对它们的使用:
ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 80);
ip::tcp::socket sock(service);
sock.connect(ep);
// TCP socket can reuse address
ip::tcp::socket::reuse_address ra(true);
sock.set_option(ra);
// get sock receive buffer size
ip::tcp::socket::receive_buffer_size rbs;
sock.get_option(rbs);
std::cout << rbs.value() << std::endl;
// set sock‘s buffer size to 8192
ip::tcp::socket::send_buffer_size sbs(8192);
sock.set_option(sbs);
[?在上述特性工作之前,套接字要被打开。否则,会抛出异常]