基于asio库的流式服务端/客户端配置疑问:bind与connect用法是否正确?
关于Asio UDP客户端/服务端bind与connect用法的疑问
我正在使用C++的Asio库,想要实现一组服务端与客户端,满足以下需求:
- 服务端在指定端口流式传输数据;
- 客户端连接该端口并接收数据。
在常规的客户端/服务端应用中,服务端会监听某个端口,客户端则连接该端口。但我实现的代码似乎颠倒了这一模式:
服务端代码
#include <iostream> #include <numeric> #include <vector> #include "asio.hpp" int main() { constexpr int size = 10; std::vector<int> vct(size); std::iota(vct.begin(), vct.end(), 0); asio::io_context context; asio::ip::udp::resolver resolver{context}; asio::ip::udp::socket socket{context}; socket.open(asio::ip::udp::v4()); socket.connect(asio::ip::udp::endpoint(asio::ip::udp::v4(), 10888)); size_t len = socket.send(asio::buffer(vct)); std::cout << "Sent " << len << " b." << std::endl; return EXIT_SUCCESS; }
客户端代码
#include <iostream> #include <vector> #include "asio.hpp" int main() { constexpr int size = 10; std::vector<int> vct(size); asio::io_context context; asio::ip::udp::endpoint local_endpoint{asio::ip::address::from_string("127.0.0.1"), 10888}; asio::ip::udp::endpoint sender_endpoint; asio::ip::udp::socket socket{context}; socket.open(asio::ip::udp::v4()); socket.bind(local_endpoint); size_t len = socket.receive_from(asio::buffer(vct), sender_endpoint); std::cout << "Received " << len << " b from " << sender_endpoint << std::endl; for (auto i : vct) std::cout << i << std::endl; return EXIT_SUCCESS; }
我在服务端中使用了connect,客户端中使用了bind,尽管代码似乎能正常运行,但我对此存在疑问:
- 这种方式是否是配置"流式服务端"与接收端的正确做法(暂不考虑异步相关问题,仅关注连接层面)?
- 是否应该以这种方式使用bind和connect?
解答
问题1:这不是流式服务端的正确配置
首先要明确:你当前用的是UDP协议,而UDP是无连接的数据包协议,根本没有"流式传输"的特性——流式传输是TCP协议的核心特性,TCP是面向连接的,能保证数据有序、可靠地流式传输。
如果要实现你需求中的"流式服务端",你应该改用TCP协议:
- TCP服务端需要创建socket后,调用
bind绑定端口,再listen监听连接,最后通过accept接收客户端的连接请求,建立流式通信; - TCP客户端则是创建socket后,调用
connect连接到服务端的绑定端口,之后就能通过socket进行流式的读写。
你当前的UDP代码只是实现了单向的数据包发送接收,和"流式传输"完全不是一个概念,所以这种方式不符合你最初的需求。
问题2:这种bind和connect的用法不符合常规客户端/服务端设计
先理清UDP中bind和connect的实际作用:
bind:给socket绑定本地IP和端口,告诉系统这个socket要处理发往该端口的数据包;connect:UDP的connect和TCP的连接完全不同,它只是给socket设置一个默认的目标端点,之后可以用send代替send_to(不用每次指定目标),但UDP本身仍然是无连接的,不会建立握手。
你的代码写法颠倒了常规角色:
- 正常UDP服务端应该是
bind到指定端口,这样才能接收任意客户端发来的数据包; - 正常UDP客户端不需要主动
bind(除非你要固定客户端的本地端口),直接用send_to发送到服务端的绑定端口即可,或者用connect指定默认目标后用send。
虽然你的代码能正常传输数据,但这种写法混淆了客户端和服务端的职责,不利于扩展(比如服务端要同时接收多个客户端的数据包时,你的写法就无法实现),所以不推荐这么用。
内容的提问来源于stack exchange,提问作者MaPo
相关产品推荐
相关产品推荐

