- ROS-I simple_message 源码分析:UdpSoc
- ROS-I simple_message 源码分析:Messag
- ROS-I simple_message 源码分析:SmplMs
- ROS-I simple_message 源码分析:Messag
- ROS-I simple_message 源码分析:JointT
- ROS-I simple_message 源码分析:JointT
- ROS-I simple_message 源码分析:JointT
- ROS-I simple_message 源码分析:TypedM
- ROS-I simple_message 源码分析:RobotS
- ROS-I simple_message 源码分析:JointT
namespace industrial
{
namespace udp_socket
{
class UdpSocket : public industrial::simple_socket::SimpleSocket
{
public:
UdpSocket();
~UdpSocket();
protected:
//udp socket连接握手号
static const char CONNECT_HANDSHAKE = 142;
char udp_read_buffer_[MAX_BUFFER_SIZE + 1];
char* udp_read_head_;
size_t udp_read_len_;
// Virtual
int rawSendBytes(char *buffer,
industrial::shared_types::shared_int num_bytes);
int rawReceiveBytes(char *buffer,
industrial::shared_types::shared_int num_bytes);
bool rawPoll(int timeout, bool & ready, bool & error);
};
} //udp_socket
} //industrial
rawSendBytes
int UdpSocket::rawSendBytes(char *buffer, shared_int num_bytes)
{
int rc = this->SOCKET_FAIL;
rc = SEND_TO(this->getSockHandle(), buffer,
num_bytes, 0, (sockaddr *)&this->sockaddr_,
sizeof(this->sockaddr_));
return rc;
}
rawSendBytes调用的是sendto函数,用于发送未建立连接的UDP数据包。
rawReceiveBytes
int UdpSocket::rawReceiveBytes(char *buffer, shared_int num_bytes)
{
int rc, len_cpy;
SOCKLEN_T addrSize;
if(udp_read_len_ == 0) {
// there is currently no data in the temporary buffer, do a socket read
addrSize = sizeof(this->sockaddr_);
rc = RECV_FROM(this->getSockHandle(), &this->udp_read_buffer_[0], this->MAX_BUFFER_SIZE,
0, (sockaddr *)&this->sockaddr_, &addrSize);
if(rc <= 0)
return 0; // either we had an error or read no data, don't update the buffer
udp_read_head_ = this->udp_read_buffer_;
udp_read_len_ = rc;
}
if(num_bytes == 0 || num_bytes >= udp_read_len_) // read all data available
len_cpy = udp_read_len_;
else
len_cpy = num_bytes;
memcpy(buffer, udp_read_head_, len_cpy);
udp_read_head_ += len_cpy; // shift pointer in buffer
udp_read_len_ -= len_cpy;
return len_cpy;
}
rawReceiveBytes会先检查本地的udp_read_buffer_中是否还有数据未被读取,有的话则先返回本地未读取的数据,没有则调用recvfrom从sockaddr_指定的地址接收数据。与TcpSocket 接收方法不同的是,这里以MAX_BUFFER_SIZE作为参数,以便一次获取最多的字节数据。
rawPoll
bool UdpSocket::rawPoll(int timeout, bool & ready, bool & error)
{
if(udp_read_len_ > 0) {
// 本地buffer还有数据未读取,先从本地读取
ready = true;
error = false;
return true;
}
timeval time;
fd_set read, write, except;
int rc = this->SOCKET_FAIL;
bool rtn = false;
ready = false;
error = false;
// The select function uses the timeval data structure
time.tv_sec = timeout / 1000;
time.tv_usec = (timeout % 1000) * 1000;
FD_ZERO(&read);
FD_ZERO(&write);
FD_ZERO(&except);
FD_SET(this->getSockHandle(), &read);
FD_SET(this->getSockHandle(), &except);
rc = SELECT(this->getSockHandle() + 1, &read, &write, &except, &time);
if (this->SOCKET_FAIL != rc) {
if (0 == rc)
rtn = false;
else {
if (FD_ISSET(this->getSockHandle(), &read)) {
ready = true;
rtn = true;
}
else if(FD_ISSET(this->getSockHandle(), &except)) {
error = true;
rtn = true;
}
else {
LOG_WARN("Select returned, but no flags are set");
rtn = false;
}
}
} else {
this->logSocketError("Socket select function failed", rc, errno);
rtn = false;
}
return rtn;
}
rawPoll实现查询功能,返回是否有数据可读或是否发生异常,与TcpSocket的rawPoll实现是类似的。
网友评论