ClientSocket::ClientSocket(const char *host, int port) { // construct network address for server struct addrinfo hint; std::memset(&hint, 0, sizeof(hint)); hint.ai_family = AF_INET; hint.ai_socktype = SOCK_STREAM; struct addrinfo* infolist{ nullptr }; int gai_error = ::getaddrinfo(host, std::to_string(port).c_str(), &hint, &infolist); if (gai_error) { std::ostringstream oss; oss << "getaddrinfo error " << gai_error << ": " << gai_strerror(gai_error) << " (" << __FILE__ << ":" << __LINE__ << ")"; throw ConnectionException(oss.str()); } // wrap our list pointer inside unique_ptr for auto cleanup #if defined(__APPLE__) || defined(__linux__) using cleanup_func = void(*)(struct addrinfo*); std::unique_ptr<struct addrinfo, cleanup_func> list{ infolist, ::freeaddrinfo }; #else // Windows using cleanup_func = void(__stdcall*)(PADDRINFOA); std::unique_ptr<struct addrinfo, cleanup_func> list(infolist, ::freeaddrinfo); #endif // create socket throw_if_min1(sock = ::socket(list->ai_family, list->ai_socktype, list->ai_protocol)); // connect to server throw_if_min1(::connect(sock, (struct sockaddr*)list->ai_addr, list->ai_addrlen)); }
ServerSocket::ServerSocket(int port) { throw_if_min1(sock = ::socket(AF_INET, SOCK_STREAM, 0)); struct sockaddr_in saServer; saServer.sin_family = AF_INET; saServer.sin_addr.s_addr = INADDR_ANY; saServer.sin_port = htons(port); throw_if_min1(::bind(sock, (struct sockaddr*)&saServer, sizeof(struct sockaddr))); throw_if_min1(::listen(sock, 100)); // the number of clients that can be queued }
void Socket::close() { std::cerr << "will close socket " << sock << std::endl; #if defined(__APPLE__) || defined(__linux__) throw_if_min1(::close(sock)); #else ::closesocket(sock); #endif sock = 0; }
ssize_t Socket::read(char *buf, size_t maxlen) { ssize_t len = 0; // might come in parts while (ssize_t n = ::recv(sock, buf + len, int(maxlen - len), 0)) { throw_if_min1((int)n); len += n; if (len >= maxlen) break; } return len; }
Socket *ServerSocket::accept() { struct sockaddr client_addr; client_addr.sa_family = AF_INET; socklen_t len = sizeof(client_addr); int fd; throw_if_min1(fd = ::accept(sock, &client_addr, &len)); Socket* client = new Socket(fd, client_addr); std::cerr << "Connection accepted from " << client->get_dotted_ip() << ", with socket " << fd << std::endl; return client; }
std::string Socket::readline() { // read a line: ignore '\r', stop at '\n' std::string line; char c; while (ssize_t n = ::recv(sock, &c, 1, 0)) { throw_if_min1((int)n); if (c == '\n') break; if (c != '\r') line += c; } return line; }
void Socket::write(const char *buf, size_t len) { throw_if_min1((int)::send(sock, buf, (int)len, 0)); }