-
Notifications
You must be signed in to change notification settings - Fork 1
/
UDPClient.cpp
154 lines (137 loc) · 3.91 KB
/
UDPClient.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//
// UDPClient.cpp
//
// Created by numata on 2017/06/08.
// Copyright © 2017 Satoshi Numata. All rights reserved.
//
#include "UDPClient.hpp"
#include <stdexcept>
#ifdef _WIN32
#pragma comment( lib, "ws2_32.lib" )
#else
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#endif
/*!
コンストラクタ
指定されたホスト名とポート番号のソケットにデータを送信するクライアントを作成します。
@param hostname_ ホスト名
@param port_ ポート番号
*/
UDPClient::UDPClient(const std::string& hostname_, int port_)
{
hostname = hostname_;
port = port_;
isClosed = true;
// ソケットの生成
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
throw std::runtime_error("Failed to create a UDP socket for sending.");
}
// ホスト名の解決
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
in_addr addr;
addr.s_addr = inet_addr(hostname_.c_str());
if (addr.s_addr == -1) {
hostent *host = gethostbyname(hostname.c_str());
if (!host) {
throw std::runtime_error("Failed to get a host entry.");
}
memcpy(&addr, (in_addr *)*host->h_addr_list, sizeof(in_addr));
}
hostname = std::string(inet_ntoa(addr));
serverAddr.sin_addr = addr;
isClosed = false;
}
/*!
デストラクタ
*/
UDPClient::~UDPClient()
{
Close();
}
/*!
接続先のホスト名(IPアドレス)を取得します。
@return 接続先のホスト名
*/
std::string UDPClient::GetRemoteHost() const
{
return hostname;
}
/*!
接続先のポート番号を取得します。
@return 接続先のポート番号
*/
int UDPClient::GetRemotePort() const
{
return port;
}
/*!
ソケットをクローズします。
*/
void UDPClient::Close()
{
if (isClosed) {
return;
}
#ifdef _WIN32
closesocket(sock);
#else
close(sock);
#endif
sock = -1;
}
/*!
ソケットからデータを受信します。
TCP/IPと異なり、受信時にエラーが発生しても自動的にソケットをクローズすることはありません。
@param buffer 受信用のデータバッファ
@param length データバッファのサイズ
@return 受信したデータのバイト数。ソケットがクローズされていた場合には0、エラーの場合は-1。
*/
ssize_t UDPClient::Receive(char *buffer, size_t length)
{
sockaddr_in fromAddr;
socklen_t fromAddrLen = sizeof(fromAddr);
return recvfrom(sock, buffer, length, 0, (sockaddr *)&fromAddr, &fromAddrLen);
}
/*!
ソケットから文字列データを受信します。
TCP/IPと異なり、受信時にエラーが発生しても自動的にソケットをクローズすることはありません。
@return 受信した文字列データ
*/
std::string UDPClient::ReceiveString()
{
ssize_t readSize = Receive(buffer, UDP_CLIENT_BUFFER_SIZE);
buffer[readSize] = '\0';
std::string ret = buffer;
return ret;
}
/*!
データを送信します。
@param buffer データのバッファ
@param length バッファのサイズ
@return 送信したデータのバイト数
*/
ssize_t UDPClient::Send(const char *buffer, size_t length)
{
if (isClosed) {
throw std::runtime_error("UDPSender::Send() was called after the socket was closed.");
}
return sendto(sock, buffer, length, 0,
(sockaddr *)&serverAddr, sizeof(serverAddr));
}
/*!
文字列データを送信します。
@param message 送信する文字列データ
@return 送信したデータのバイト数
*/
ssize_t UDPClient::Send(const std::string& message)
{
return Send(message.c_str(), message.length());
}