Skip to content

Instantly share code, notes, and snippets.

@ubnt-intrepid
Last active August 29, 2015 14:16
Show Gist options
  • Save ubnt-intrepid/338b0f5b88ab4e6b0b83 to your computer and use it in GitHub Desktop.
Save ubnt-intrepid/338b0f5b88ab4e6b0b83 to your computer and use it in GitHub Desktop.
#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;
#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;
#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)
;
}
#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