Last active
August 29, 2015 14:16
-
-
Save ubnt-intrepid/338b0f5b88ab4e6b0b83 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "socketapi.hpp" | |
namespace network { | |
using boost::optional; | |
namespace ph = std::placeholders; | |
// @brief リスナソケットを生成する | |
// @param port :: unsigned short ソケットをbindするポート番号 | |
// @retval 作成したソケットのディスクリプタ | |
optional<basic_socket> make_listener(unsigned short port) { | |
return make_tcp_socket() | |
| std::bind(bind_to, ph::_1, port) | |
| std::bind(listen, ph::_1, 5); | |
} | |
// @brief 指定IP,portのサーバとの通信用のソケットを作成する | |
// @param ip :: std::string 接続先のIPアドレス | |
// @param port :: unsigned short 接続先のポート番号 | |
// @retval 接続先の確立に成功すれば有効値が返る | |
optional<basic_socket> make_connection(std::string const& ip, unsigned short port) { | |
return make_tcp_socket() | |
| std::bind(connect, ph::_1, ip, port); | |
} | |
} // namspace network; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#if defined(_MSC_VER) | |
# include <winsock2.h> | |
# include <ws2tcpip.h> | |
#else | |
# include <sys/socket.h> | |
# include <sys/select.h> | |
# include <sys/time.h> | |
# include <sys/types.h> | |
# include <unistd.h> | |
# include <netdb.h> | |
#endif | |
#include <boost/optional.hpp> | |
namespace boost { | |
template <typename T, typename UnaryF> | |
typename std::result_of<UnaryF(T)>::type operator |(optional<T> const& lhs, UnaryF f) | |
{ | |
if (!lhs) return none; | |
return f(lhs.get()); | |
} | |
template <typename T, typename UnaryF> | |
typename std::result_of<UnaryF(T)>::type operator |(optional<T> && lhs, UnaryF f) | |
{ | |
if (!lhs) return none; | |
return f(lhs.get()); | |
} | |
template <typename Pred, typename T> | |
optional<T> make_optional(Pred pred, T const& val) { | |
return make_optional(pred(val), val); | |
} | |
} // namespace boost; | |
namespace std { | |
template <typename T> | |
function<bool(T const&)> not_equal_to(T const& rhs) { | |
return [&rhs](T const& lhs){ return lhs != rhs; }; | |
} | |
} // namespace std; | |
namespace network { | |
using boost::optional; | |
class basic_socket { | |
SOCKET s_; | |
public: | |
explicit basic_socket(SOCKET s): s_(s) {} | |
explicit operator SOCKET () const { return s_; } | |
~basic_socket() | |
{ | |
::shutdown(s_, SD_BOTH); | |
::closesocket(s_); | |
} | |
}; | |
optional<basic_socket> make_tcp_socket() { | |
return make_optional(not_equal_to(INVALID_SOCKET), ::socket(AF_INET, SOCK_STREAM, 0)); | |
} | |
optional<basic_socket> make_udp_socket() { | |
return make_optional(not_equal_to(INVALID_SOCKET), ::socket(AF_INET, SOCK_DGRAM, 0)); | |
} | |
::sockaddr_in make_addr(unsigned short port) { | |
::sockaddr_in addr; | |
addr.sin_family = AF_INET; | |
addr.sin_port = htons(port); | |
addr.sin_addr.S_un.S_addr = INADDR_ANY; | |
return addr; | |
} | |
::sockaddr_in make_addr(std::string const& ip, unsigned short port) { | |
::sockaddr_in addr; | |
return addr; | |
} | |
optional<basic_socket> bind_to(SOCKET s, unsigned short port) { | |
::sockaddr_in addr = make_addr(port); | |
return make_optional(not_equal_to(SOCKET_ERROR), ::bind(s, &addr, sizeof(addr))); | |
} | |
optional<basic_socket> listen(SOCKET s, int backlog) { | |
return make_optional(not_equal_to(SOCKET_ERROR), ::listen(s, backlog)); | |
} | |
optional<std::pair<basic_socket, sockaddr_in>> accept(SOCKET sock) { | |
sockaddr_in addr; | |
int len = sizeof(addr); | |
SOCKET s = ::accept(sock, &addr, &len); | |
return make_optional(s != INVALID_SOCKET && len == sizeof(addr), std::make_pair(s, addr)); | |
} | |
optional<basic_socket> connect(SOCKET sock, std::string const& ip, unsigned short port) { | |
sockaddr_in addr = make_addr(ip, port); | |
return make_optional(not_equal_to(INVALID_SOCKET), ::connect(sock, (sockaddr*)&addr, sizeof(addr))); | |
} | |
} // namspace network; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "socket.hpp" | |
#include "format.h" | |
optional<std::string> send_request(SOCKET s, std::string const& msg) | |
{ | |
network::send(s, msg); | |
return network::recv(s); | |
} | |
int main() | |
{ | |
using std::placeholders::_1; | |
network::make_connction("localhost", 9000) | |
| std::bind(send_request, _1, "Hello, server.") | |
| std::bind(fmt::print, "response: {0}", _1) | |
; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "socket.hpp" | |
#include "format.h" | |
std::string make_response(std::string const& request) { | |
return fmt::format("request is: \"{0}\"", request); | |
} | |
int main(int argc, char** argv) | |
{ | |
// create a listener socket. | |
if (auto listener = network::make_listener(9000)) | |
{ | |
// accept a connection from a client. | |
if (auto ret = network::detail::accept(listener.get())) { | |
SOCKET s = ret->first; | |
sockaddr_in const& addr = ret->second; | |
// send a welcome message. | |
network::send(s, fmt::format("Hello, {0}.", network::to_str(addr))); | |
// wait a request to the client and send the response. | |
if (auto request = network::recv(s)) | |
{ | |
network::send(s, make_response(request.get())); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment