/***************************************udpclient.h******************************/
#ifndef UDP_CLIENT_H
#define UDP_CLIENT_H
#include <winsock.h>
class Clientudp
{
public:
Clientudp();
bool InitializeClient(const char* ip, int local_port, int remote_port = -1);
void SetReadTimeout(int timeout_ms);
int PushToWriteBuffer(const char* msg, unsigned int size);
int PullFromReadBuffer(char* msg, unsigned int size);
bool GetClientStatus();
bool GetRemoteAddress(sockaddr_in* addr);
~Clientudp();
private:
int m_fd_;
int m_read_timeout = -1;
bool m_socket_avaliable_ = false;
sockaddr_in m_remote_addr_;
int m_remote_port_ = -1;
sockaddr_in m_bind_addr_;
};
#endif
/*************************************udpclient.cpp***************************/
#include <iostream>
#include "UdpClient.h"
Clientudp::Clientudp()
{}
Clientudp::~Clientudp()
{
if(m_socket_avaliable_)
closesocket(m_fd_);
}
void Clientudp::SetReadTimeout(int timeout_ms)
{
m_read_timeout = timeout_ms;
}
bool Clientudp::InitializeClient(const char* ip, int local_port, int remote_port)
{
if (m_socket_avaliable_)
{
closesocket(m_fd_);
m_socket_avaliable_ = false;
}
if ((m_fd_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
// create socket failed.
m_socket_avaliable_ = false;
return m_socket_avaliable_;
}
if (m_read_timeout > 0)
{
struct timeval read_timeout = { m_read_timeout, 0 };
setsockopt(m_fd_, SOL_SOCKET, SO_RCVTIMEO, (char *)&read_timeout, sizeof(struct timeval));
}
memset(&m_remote_addr_, 0, sizeof(m_remote_addr_));
m_remote_addr_.sin_family = AF_INET;
m_remote_addr_.sin_addr.s_addr = inet_addr(ip);
m_remote_addr_.sin_port = htons(remote_port);
m_remote_port_ = remote_port;
memset(&m_bind_addr_, 0, sizeof(m_bind_addr_));
m_bind_addr_.sin_family = AF_INET;
m_bind_addr_.sin_addr.s_addr = htonl(INADDR_ANY);
m_bind_addr_.sin_port = htons(local_port);
if (bind(m_fd_, (SOCKADDR*)&m_bind_addr_, sizeof(m_bind_addr_)) == SOCKET_ERROR)
{
int error_code = WSAGetLastError();
if (error_code == WSAEADDRINUSE)
printf("The port %d on this machine has been Occqupied.\n", local_port);
printf("Bind Client to Fixed address Failed, Then you should settle a correct remote port and send data to remote machine before recv.\n");
if (m_remote_port_ <= 0)
{
printf("InitializeClient Failed, Remote port = %d seems not to be a valid port number.\n", m_remote_port_);
closesocket(m_fd_);
m_socket_avaliable_ = false;
return false;
}
}
m_socket_avaliable_ = true;
return m_socket_avaliable_;
}
int Clientudp::PushToWriteBuffer(const char* msg, unsigned int size)
{
if (!m_socket_avaliable_)
{
return -1;
}
int ret = sendto(m_fd_, msg, size, 0, (sockaddr*)&m_remote_addr_, sizeof(m_remote_addr_));
if (ret == SOCKET_ERROR)
{
int error_code = WSAGetLastError();
//printf("error_code: %d\n",error_code);
if (m_remote_port_ < 0 && error_code == WSAEINVAL)
{
printf("You should recv data from peer firstly before send.\n");
return 0;
}
closesocket(m_fd_);
m_socket_avaliable_ = false;
m_remote_port_ = -1;
return -1;
}
else
{
return ret;
}
}
int Clientudp::PullFromReadBuffer(char* msg, unsigned int size)
{
if (!m_socket_avaliable_)
{
return -1;
}
int addr_len = sizeof(m_remote_addr_);
int ret = recvfrom(m_fd_, msg, size, 0, (sockaddr*)&m_remote_addr_, &addr_len);
if (ret == SOCKET_ERROR)
{
int error_code = WSAGetLastError();
if (error_code == WSAEMSGSIZE || error_code == WSAEINTR || error_code == WSAETIMEDOUT || error_code == WSAEWOULDBLOCK)
{
if(error_code == WSAEMSGSIZE)//datagram is too large to put into msg buffer.
memset(msg,0x00,size);
return 0;
}
else
{
closesocket(m_fd_);
m_socket_avaliable_ = false;
return -1;
}
}
else
{
return ret;
}
}
bool Clientudp::GetClientStatus()
{
return m_socket_avaliable_;
}
bool Clientudp::GetRemoteAddress(sockaddr_in* addr)
{
if(!m_socket_avaliable_)
return false;
if (m_remote_port_ <= 0)
{
int asize;
getpeername(m_fd_, (sockaddr*)&m_remote_addr_, &asize);
m_remote_port_ = ntohs(m_remote_addr_.sin_port);
if (m_remote_port_ <= 0)
return false;
}
*addr = m_remote_addr_;
return true;
}
#include <iostream>
#include "udpclient.h"
int main()
{
WSADATA ws
WSAStartup(MAKEWORD(2,2),&ws);
Clientudp udp;
udp.InitializeClient("127.0.0.1", 1234, -1);
char RxBuffer[1024];
char TxBuffer[1024];
memset(RxBuffer,0x00,1024);
memset(TxBuffer,0x00,1024);
/*如果remote_port为-1,则目的端口号未知,只能先收再发。如果知道对方端口号,则收发顺序可随便*/
int readLen= udp.PullFromReadBuffer(RxBuffer,1024);
printf("Read message length: %d",readLen);
int writeLen = sprintf_s(TxBuffer,1023,"hello world");
udp.PushToWriteBuffer(TxBuffer,writeLen);
getchar();
WSACleanup();
return 0;
}