Opened 11 years ago
#6661 new Bugs
Different behavior on WIN and Linux
Reported by: | Owned by: | chris_kohlhoff | |
---|---|---|---|
Milestone: | To Be Determined | Component: | asio |
Version: | Boost 1.49.0 | Severity: | Problem |
Keywords: | udp, available, receive | Cc: |
Description
Hi, I've found a different behavior at use of some functions with UDP protocol.
Look at this code
io_service ios; udp::endpoint to(address::from_string("127.0.0.1"), port); udp::socket sender(ios, udp::v4()); udp::socket receiver(ios, udp::endpoint(udp::v4(), port)); const char buf[] = "Some test data..."; const size_t buf_len = sizeof(buf); char read_buf[buf_len]; char half_read_buf[buf_len / 2]; sender.send_to(buffer(buf, buf_len), to); try { udp::endpoint sender_point; receiver.receive_from(buffer(half_read_buf, sizeof(half_read_buf)), sender_point); } catch(exception& ex) { string str = ex.what(); cerr << "Exception: "<< ex.what() << endl; } cout << string(half_read_buf, sizeof(half_read_buf)) << endl; sender.send_to(buffer(buf, buf_len), to); sender.send_to(buffer(buf, buf_len), to); cout << "Available: " << receiver.available() << endl; receiver.receive(buffer(read_buf, sizeof(read_buf))); cout << "Available: " << receiver.available() << endl; receiver.receive(buffer(read_buf, sizeof(read_buf))); cout << "Available: " << receiver.available() << endl;
Here we are reading half an datagramm and use socket::available() to look how much data into the socket. Execute this code on WIN32 and you get this output
Exception: receive_from: The message was too large for the specified buffer and (for unreliable protocols only) any trailing portion of the message that did not fit into the buffer has been discarded. Some test Available: 36 Available: 18 Available: 0
Execute it on Linux and you get
Some test Available: 18 Available: 18 Available: 0
It looks strange.
Look into source
boost/asio/detail/impl/socket_ops.ipp ------------------------------------- int recvfrom(socket_type s, buf* bufs, size_t count, int flags, socket_addr_type* addr, std::size_t* addrlen, boost::system::error_code& ec) { ... #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); *addrlen = (std::size_t)tmp_addrlen; ... if (result != 0) return socket_error_retval; ec = boost::system::error_code(); return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); init_msghdr_msg_name(msg.msg_name, addr); msg.msg_namelen = *addrlen; msg.msg_iov = bufs; msg.msg_iovlen = count; int result = error_wrapper(::recvmsg(s, &msg, flags), ec); *addrlen = msg.msg_namelen; if (result >= 0) ec = boost::system::error_code(); return result; }
For WIN32 uses functions family WSARecv(http://msdn.microsoft.com/en-us/library/windows/desktop/ms741686(v=vs.85).aspx) they return status of error. And one of which is
WSAEMSGSIZE The message was too large for the specified buffer and (for unreliable protocols only) any trailing portion of the message that did not fit into the buffer has been discarded.
For Linux uses functions family recv (http://linux.die.net/man/2/recv). They return the length of the message on successful completion or -1 and set status in errno if was error. But for them no the error if buffer length less that a received datagram.
But if we uses function recvfrom, it sets this error into struct msghdr in the msg_flags
MSG_TRUNC indicates that the trailing portion of a datagram was discarded because the datagram was larger than the buffer supplied.
And also about function basic_datagram_socket::available. For WIN32 it returns length of all datagrams in the socket BUT for linux in returns length a one datagramm.