美文网首页
ROS-I simple_message 源码分析:UdpSoc

ROS-I simple_message 源码分析:UdpSoc

作者: play_robot | 来源:发表于2019-03-22 17:27 被阅读0次
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实现是类似的。

相关文章

网友评论

      本文标题:ROS-I simple_message 源码分析:UdpSoc

      本文链接:https://www.haomeiwen.com/subject/glervqtx.html