UdpClient继承自UdpSocket,实现了一个UDP客户端
namespace industrial
{
namespace udp_client
{
class UdpClient : public industrial::udp_socket::UdpSocket
{
public:
UdpClient();
~UdpClient();
bool makeConnect();
bool init(char *buff, int port_num);
};
} //udp_server
} //industrial
init
bool UdpClient::init(char *buff, int port_num)
{
int rc;
bool rtn;
addrinfo *result;
addrinfo hints = {};
/* Create a socket using:
* AF_INET - IPv4 internet protocol
* SOCK_DGRAM - UDP type
* protocol (0) - System chooses
*/
rc = SOCKET(AF_INET, SOCK_DGRAM, 0);
if (this->SOCKET_FAIL != rc)
{
this->setSockHandle(rc);
// Initialize address data structure
memset(&this->sockaddr_, 0, sizeof(this->sockaddr_));
this->sockaddr_.sin_family = AF_INET;
// Check for 'buff' as hostname, and use that, otherwise assume IP address
hints.ai_family = AF_INET; // IPv4
hints.ai_socktype = SOCK_DGRAM; // UDP socket
hints.ai_flags = 0;
hints.ai_protocol = 0;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
if (0 == GETADDRINFO(buff, NULL, &hints, &result))
{
this->sockaddr_ = *((sockaddr_in *)result->ai_addr);
}
else
{
this->sockaddr_.sin_addr.s_addr = INET_ADDR(buff);
}
this->sockaddr_.sin_port = HTONS(port_num);
rtn = true;
}
else
{
LOG_ERROR("Failed to create socket, rc: %d", rc);
rtn = false;
}
return rtn;
}
init完成了下一步进行连接所需的socket参数:用户传进来的IP地址和端口号转换为socket数据结构。
makeConnect
bool UdpClient::makeConnect()
{
ByteArray send;
char sendHS = this->CONNECT_HANDSHAKE;
char recvHS = 0;
bool rtn = false;
const int timeout = 1000; // Time (ms) between handshake sends
int bytesRcvd = 0;
if (!this->isConnected())
{
this->setConnected(false);
send.load((void*)&sendHS, sizeof(sendHS));
const int sendLen = send.getBufferSize();
char localBuffer[sendLen];
send.unload(localBuffer, sendLen);
do
{
ByteArray recv;
recvHS = 0;
LOG_DEBUG("UDP client sending handshake");
this->rawSendBytes(localBuffer, sendLen);
if (this->isReadyReceive(timeout))
{
bytesRcvd = this->rawReceiveBytes(this->buffer_, 0);
LOG_DEBUG("UDP client received possible handshake");
recv.init(&this->buffer_[0], bytesRcvd);
recv.unload((void*)&recvHS, sizeof(recvHS));
}
}
while(recvHS != sendHS);
LOG_INFO("UDP client connected");
rtn = true;
this->setConnected(true);
}
else
{
rtn = true;
LOG_WARN("Tried to connect when socket already in connected state");
}
return rtn;
}
客户端的makeConnect逻辑与服务器端相反,先发送握手号,再接收服务器回复的握手号,两者相等则表明“连接”建立。
至此已经分析完了simple message的所有模块,这为我们编写ROS端的client nodes和控制器端的server打下了坚实的基础。