さすがに「これはひどい」だったので、例外を使うように書き直す。
テンプレート、便利だなー。
#include <string> #include <iostream> #include <sstream> #include <winsock2.h> namespace wsa { int cleanup() { return WSACleanup(); } void startup(WORD version) { WSADATA wsa_data; int n; if ((n = WSAStartup(version, &wsa_data)) != 0) { std::cerr << "WASStartup(): " << n << "\n"; cleanup(); exit(1); } if (version != wsa_data.wVersion) { std::cerr << "WASStartup(): WinSock version " << LOWORD(version) << "." << HIWORD(version) << " not supported\n"; cleanup(); exit(1); } } } namespace echod { class Exception { std::stringstream msgbuf; public: Exception(); Exception(Exception &e); std::string message(); template<class T> Exception &operator<<(T x); }; Exception::Exception() { } Exception::Exception(const Exception &e) { //msgbuf << e.message(); msgbuf << e.msgbuf.str(); } std::string Exception::message() { return msgbuf.str(); } template<class T> Exception &Exception::operator<<(T x) { msgbuf << x; return *this; } class Server { static const int BACKLOG = 5; static const int RCVBUFSIZE = 256; int port; SOCKET socket; sockaddr_in addr; void echo(SOCKET &s); public: Server(int port = 7); void create_socket(); void bind(); void listen(); void start(); }; void Server::echo(SOCKET &s) { while (true) { char buf[RCVBUFSIZE]; size_t len = ::recv(s, buf, RCVBUFSIZE, 0); if (len < 0) { throw Exception() << "recv(): " << WSAGetLastError(); } if (len == 0) { break; } std::cout << std::string(buf, len) /*<< "\n"*/; if (::send(s, buf, len, 0) < 0) { throw Exception() << "send(): " << WSAGetLastError(); } } } Server::Server(int port) : port(port) { } void Server::create_socket() { socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (socket == INVALID_SOCKET) { throw Exception() << "socket(): " << WSAGetLastError(); } addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.S_un.S_addr = INADDR_ANY; } void Server::bind() { if (::bind(socket, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)) != 0) { throw Exception() << "bind(): " << WSAGetLastError(); } } void Server::listen() { if (::listen(socket, BACKLOG) != 0) { throw Exception() << "listen(): " << WSAGetLastError(); } } void Server::start() { while(true) { sockaddr_in caddr; int len = sizeof(caddr); std::cerr << "wait..."; SOCKET s = accept(socket, reinterpret_cast<sockaddr *>(&caddr), &len); if (s == INVALID_SOCKET) { throw Exception() << "accept(): " << WSAGetLastError(); } std::cerr << "accepted.\n"; echo(s); closesocket(s); } } } int main() { int code = 0; wsa::startup(MAKEWORD(2, 0)); try { echod::Server echod; echod.create_socket(); echod.bind(); echod.listen(); echod.start(); } catch (echod::Exception &e) { std::cerr << e.message() << "\n"; } wsa::cleanup(); return code; }
コピーコンストラクタの引数をconstにできない…なーぜー。
「msgbuf << e.message()」を「msgbuf << e.msgbuf.str()」にしたら、constにできた。
コピーコンストラクタの中でthisを参照できない?(コピー元なのに?)
あとException#<<(T &x)とかできない。なーぜー。