├── Chapter01 └── SSL_TLS.cpp ├── Chapter04 ├── Makefile ├── README ├── basic_example.cpp ├── example_tcp.cpp └── member_function_callback.cpp ├── Chapter05 ├── .gitignore ├── Makefile ├── example_DNS.cpp ├── example_TCP_client.cpp ├── example_TCP_server.cpp ├── example_TCP_server_fullerrorcheck.cpp └── example_UDP.cpp ├── Chapter06 ├── Makefile ├── README ├── client ├── example_client.cpp ├── example_server.cpp └── server ├── Chapter07 ├── .gitignore ├── Makefile ├── client.cpp └── server.cpp ├── Chapter08 ├── .gitignore ├── Makefile ├── README ├── example_asio_tcp_client.cpp ├── example_asio_tcp_server.cpp ├── example_asio_udp_client.cpp └── example_asio_udp_server.cpp ├── Chapter09 ├── client.cpp └── server.cpp ├── Chapter10 ├── Makefile ├── example_qt_tcp_client.cpp ├── example_qt_tcp_server.cpp ├── example_qt_udp_client.cpp └── example_qt_udp_server.cpp ├── Chapter12 ├── .gitignore ├── Makefile ├── client.cpp └── server.cpp ├── LICENSE └── README.md /Chapter01/SSL_TLS.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void cleanup(SSL_CTX* context, BIO* bio) 9 | { 10 | SSL_CTX_free(context); 11 | BIO_free_all(bio); 12 | } 13 | 14 | int main() 15 | { 16 | std::string hostname = "belaycpp.com:443"; 17 | 18 | // Init 19 | 20 | SSL_load_error_strings(); 21 | SSL_library_init(); 22 | 23 | // Context creation 24 | 25 | const SSL_METHOD* method = TLS_client_method(); 26 | if (method == nullptr) 27 | return 1; 28 | 29 | SSL_CTX* context = SSL_CTX_new(method); 30 | if (context == nullptr) 31 | return 1; 32 | 33 | BIO* bio = BIO_new_ssl_connect(context); 34 | if (bio == nullptr) 35 | return 1; 36 | 37 | SSL* ssl = NULL; 38 | 39 | // Connection 40 | 41 | std::string name = hostname + ":https"; 42 | BIO_get_ssl(bio, &ssl); 43 | SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); 44 | BIO_set_conn_hostname(bio, name.c_str()); 45 | int success = BIO_do_connect(bio); 46 | 47 | if (success != 1) 48 | { 49 | cleanup(context, bio); 50 | std::cerr << "Connection failed" << std::endl; 51 | return 1; 52 | } 53 | 54 | // Certificate validation 55 | 56 | success = SSL_CTX_load_verify_locations(context, "/etc/ssl/certs/ca-certificates.crt", "/etc/ssl/certs/"); 57 | if (success != 1) 58 | { 59 | cleanup(context, bio); 60 | std::cerr << "Certificate verification failed" << std::endl; 61 | return 1; 62 | } 63 | 64 | long verify_flag = SSL_get_verify_result(ssl); 65 | if (verify_flag != X509_V_OK) 66 | std::cerr << "Certificate verification error: " << verify_flag << std::endl; 67 | 68 | // Request 69 | 70 | std::string request = "GET / HTTP/1.1\x0D\x0AHost: "+hostname+"\x0D\x0A\x43onnection: Close\x0D\x0A\x0D\x0A"; 71 | BIO_puts(bio, request.c_str()); 72 | 73 | const size_t BUFF_SIZE = 1024; 74 | char response[BUFF_SIZE]; 75 | while (1) 76 | { 77 | memset(response, 0, sizeof(response)); 78 | int nread = BIO_read(bio, response, BUFF_SIZE); 79 | if (nread <= 0) 80 | break; 81 | std::cout << response; 82 | } 83 | std::cout << std::endl; 84 | 85 | // Cleanup 86 | 87 | cleanup(context, bio); 88 | 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /Chapter04/Makefile: -------------------------------------------------------------------------------- 1 | CC = g++ 2 | CFLAGS = -lcurl 3 | 4 | basic_example: basic_example.cpp 5 | $(CC) -o $@ $^ $(CFLAGS) 6 | 7 | example_tcp: example_tcp.cpp 8 | $(CC) -o $@ $^ $(CFLAGS) 9 | 10 | member_function_callback: member_function_callback.cpp 11 | $(CC) -o $@ $^ $(CFLAGS) 12 | 13 | all: basic_example example_tcp member_function_callback 14 | 15 | 16 | clean: 17 | rm -f basic_example 18 | rm -f example_tcp 19 | rm -f member_function_callback 20 | 21 | help: 22 | cat ./README 23 | -------------------------------------------------------------------------------- /Chapter04/README: -------------------------------------------------------------------------------- 1 | Prerequisite: libcurl 2 | 3 | Here are the different command lines to build the examples 4 | 5 | make basic_example 6 | make example_tcp 7 | make member_function_callback 8 | 9 | You also have the possibility to build all, clean and show help 10 | 11 | make all 12 | make clean 13 | make help 14 | 15 | -------------------------------------------------------------------------------- /Chapter04/basic_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | CURL * curl; 7 | CURLcode ecode; 8 | CURLU * url; 9 | CURLUcode ucode; 10 | char * host; 11 | char * path; 12 | 13 | curl = curl_easy_init(); 14 | if(curl == NULL) 15 | { 16 | std::cerr << "Error on init [" << ecode << "]" << std::endl; 17 | return 1; 18 | } 19 | 20 | // Gets an url 21 | url = curl_url(); 22 | if(!url) 23 | return 1; 24 | 25 | // Parse an URL 26 | ucode = curl_url_set(url, CURLUPART_URL, "https://belaycpp.com/team/", 0); 27 | if(ucode != CURLUE_OK) 28 | { 29 | std::cerr << "Error on URL set [" << ucode << "]" << std::endl; 30 | curl_url_cleanup(url); 31 | return 1; 32 | } 33 | 34 | // Get the host name from the URL 35 | ucode = curl_url_get(url, CURLUPART_HOST, &host, 0); 36 | if(ucode == CURLUE_OK) 37 | { 38 | std::cout << "Host name: " << host << std::endl; 39 | curl_free(host); 40 | } 41 | 42 | // Gets the path from the URL 43 | ucode = curl_url_get(url, CURLUPART_PATH, &path, 0); 44 | if(ucode == CURLUE_OK) 45 | { 46 | std::cout << "Path: " << path << std::endl; 47 | curl_free(path); 48 | } 49 | 50 | ecode = curl_easy_setopt(curl, CURLOPT_CURLU, url); 51 | if(ecode != CURLE_OK) 52 | { 53 | std::cerr << "Error on setopt [" << ecode << "]" << std::endl; 54 | curl_url_cleanup(url); 55 | return 1; 56 | } 57 | 58 | ecode = curl_easy_perform(curl); 59 | if(ecode != CURLE_OK) 60 | { 61 | std::cerr << "Error on perform [" << ecode << "]" << std::endl; 62 | curl_url_cleanup(url); 63 | return 1; 64 | } 65 | 66 | curl_url_cleanup(url); 67 | 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /Chapter04/example_tcp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Function that is used to wait on a socket 5 | static int wait(curl_socket_t sock, bool receive_mode, long timeout_ms) 6 | { 7 | timeval tv; 8 | tv.tv_usec = (timeout_ms % 1000) * 1000; 9 | tv.tv_sec = timeout_ms / 1000; 10 | 11 | fd_set in_fd, out_fd, error_fd; 12 | FD_ZERO(&in_fd); 13 | FD_ZERO(&out_fd); 14 | FD_ZERO(&error_fd); 15 | 16 | FD_SET(sock, &error_fd); 17 | 18 | if(receive_mode) 19 | FD_SET(sock, &in_fd); 20 | else 21 | FD_SET(sock, &out_fd); 22 | 23 | // select return the number of activated sockets 24 | int nsockets = select(static_cast(sock) + 1, &in_fd, &out_fd, &error_fd, &tv); 25 | return nsockets; 26 | } 27 | 28 | int main(void) 29 | { 30 | CURL * curl; 31 | curl = curl_easy_init(); 32 | const long TIMEOUT = 60000L; 33 | const size_t BUFF_SIZE = 1024; 34 | 35 | if(curl) 36 | { 37 | // Setting the URL and the options 38 | 39 | curl_easy_setopt(curl, CURLOPT_URL, "https://belaycpp.com"); 40 | curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L); 41 | 42 | // Connection 43 | 44 | CURLcode ecode = curl_easy_perform(curl); 45 | 46 | if(ecode != CURLE_OK) 47 | { 48 | std::cerr << "Error: " << curl_easy_strerror(ecode) << std::endl; 49 | return 1; 50 | } 51 | 52 | // Getting info on the socket 53 | 54 | curl_socket_t sock; 55 | ecode = curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sock); 56 | 57 | if(ecode != CURLE_OK) 58 | { 59 | std::cerr << "Error: " << curl_easy_strerror(ecode) << std::endl; 60 | return 1; 61 | } 62 | 63 | // Sending request 64 | std::cout << "Sending request..." << std::endl; 65 | 66 | std::string request = "GET / HTTP/1.0\r\nHost: belaycpp.com\r\n\r\n"; 67 | size_t nsent_total = 0; 68 | 69 | // Looping in case the message is fragmented 70 | do 71 | { 72 | size_t nsent = 0; 73 | do 74 | { 75 | nsent = 0; 76 | ecode = curl_easy_send(curl, request.c_str() + nsent_total, request.size() - nsent_total, &nsent); 77 | nsent_total += nsent; 78 | 79 | if(ecode == CURLE_AGAIN && wait(sock, false, TIMEOUT) == 0) 80 | { 81 | std::cerr << "Error: timeout\n" << std::endl; 82 | return 1; 83 | } 84 | } while(ecode == CURLE_AGAIN); // "AGAIN" means we have to send the message again 85 | 86 | if(ecode != CURLE_OK) 87 | { 88 | std::cerr << "Error: %s\n" << curl_easy_strerror(ecode) << std::endl; 89 | return 1; 90 | } 91 | 92 | printf("Sent %lu bytes.\n", static_cast(nsent)); 93 | 94 | } while(nsent_total < request.size()); 95 | 96 | // Reading response 97 | std::cout << "Reading response..." << std::endl; 98 | 99 | // Looping until we receive no more 100 | size_t nread = 0; 101 | do 102 | { 103 | char buffer[BUFF_SIZE]; 104 | do 105 | { 106 | nread = 0; 107 | ecode = curl_easy_recv(curl, buffer, sizeof(buffer), &nread); 108 | 109 | if(ecode == CURLE_AGAIN && wait(sock, true, TIMEOUT) == 0) 110 | { 111 | std::cerr << "Error: timeout" << std::endl; 112 | return 1; 113 | } 114 | } while(ecode == CURLE_AGAIN); 115 | 116 | if(ecode != CURLE_OK) 117 | { 118 | std::cerr << "Error: " << curl_easy_strerror(ecode) << std::endl; 119 | return 1; 120 | } 121 | 122 | if(nread != 0) 123 | std::cout << "Received " << nread << " bytes" << std::endl; 124 | 125 | } while(nread != 0); 126 | 127 | // Cleanup 128 | 129 | curl_easy_cleanup(curl); 130 | } 131 | return 0; 132 | } 133 | -------------------------------------------------------------------------------- /Chapter04/member_function_callback.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Foo 4 | { 5 | // Function we want to "set" as callback 6 | int my_read(char *buffer, size_t size, size_t nitems) { return 0; } 7 | 8 | // Wraping the f function in a static member funciton 9 | static int static_f(char *buffer, size_t size, size_t nitems, void *userdata) 10 | { 11 | return static_cast(userdata)->my_read(buffer, size, nitems); 12 | } 13 | }; 14 | 15 | 16 | int main() 17 | { 18 | CURLU * handle = curl_url(); 19 | if(!handle) 20 | return 1; 21 | 22 | Foo foo; 23 | 24 | // Here, we pass our member function as a callback 25 | // using the static function that wraps the function my_read 26 | curl_easy_setopt(handle, CURLOPT_READFUNCTION, Foo::static_f); 27 | curl_easy_setopt(handle, CURLOPT_READDATA, &foo); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /Chapter05/.gitignore: -------------------------------------------------------------------------------- 1 | dns 2 | tcp_client 3 | tcp_server 4 | tcp_server_fullerrorcheck 5 | udp 6 | *.swp 7 | *.swo 8 | -------------------------------------------------------------------------------- /Chapter05/Makefile: -------------------------------------------------------------------------------- 1 | CC = g++ 2 | CFLAGS = -luv 3 | 4 | all: dns tcp_client tcp_server tcp_server_fullerrorcheck udp 5 | 6 | clean: 7 | rm -f dns 8 | rm -f tcp_client 9 | rm -f tcp_server 10 | rm -f tcp_server_fullerrorcheck 11 | rm -f udp 12 | 13 | 14 | dns: example_DNS.cpp 15 | $(CC) -o $@ $^ $(CFLAGS) 16 | 17 | tcp_client: example_TCP_client.cpp 18 | $(CC) -o $@ $^ $(CFLAGS) 19 | 20 | tcp_server: example_TCP_server.cpp 21 | $(CC) -o $@ $^ $(CFLAGS) 22 | 23 | tcp_server_fullerrorcheck: example_TCP_server_fullerrorcheck.cpp 24 | $(CC) -o $@ $^ $(CFLAGS) 25 | 26 | udp: example_UDP.cpp 27 | $(CC) -o $@ $^ $(CFLAGS) 28 | -------------------------------------------------------------------------------- /Chapter05/example_DNS.cpp: -------------------------------------------------------------------------------- 1 | // g++ example_DNS.cpp -luv 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | 9 | void on_resolved(uv_getaddrinfo_t *resolver, int status, struct addrinfo *res) 10 | { 11 | if (status == -1) 12 | { 13 | std::cerr << "getaddrinfo callback error" << std::endl; 14 | return; 15 | } 16 | 17 | char addr[17] = {'\0'}; 18 | uv_ip4_name(reinterpret_cast(res->ai_addr), addr, 16); 19 | std::cerr << addr << std::endl; 20 | 21 | // Connect and do stuff 22 | 23 | uv_freeaddrinfo(res); 24 | } 25 | 26 | int main() 27 | { 28 | uv_loop_t *loop = uv_default_loop(); 29 | 30 | addrinfo hints; 31 | hints.ai_family = PF_INET; 32 | hints.ai_socktype = SOCK_STREAM; 33 | hints.ai_protocol = IPPROTO_TCP; 34 | hints.ai_flags = 0; 35 | 36 | uv_getaddrinfo_t resolver; 37 | std::cerr << "belaycpp.com is... "; 38 | int r = uv_getaddrinfo(loop, &resolver, on_resolved, "belaycpp.com", "80", &hints); 39 | 40 | if (r) 41 | { 42 | std::cerr << "getaddrinfo call error" << std::endl; 43 | return 1; 44 | } 45 | return uv_run(loop, UV_RUN_DEFAULT); 46 | } 47 | -------------------------------------------------------------------------------- /Chapter05/example_TCP_client.cpp: -------------------------------------------------------------------------------- 1 | // g++ example_TCP_client.cpp -luv 2 | 3 | #include 4 | #include 5 | 6 | 7 | static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) 8 | { 9 | *buf = uv_buf_init(new char[size], size); 10 | } 11 | 12 | void on_close(uv_handle_t* handle) 13 | { 14 | std::cout << "Closed." << std::endl; 15 | } 16 | 17 | void on_write(uv_write_t* req, int status) 18 | { 19 | if (status) 20 | { 21 | std::cerr << "uv_write error " << std::endl; 22 | return; 23 | } 24 | std::cout << "wrote." << std::endl; 25 | delete req; 26 | } 27 | 28 | void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) 29 | { 30 | if(nread >= 0) 31 | std::cout << "Read: " << buf->base << std::endl; 32 | else 33 | uv_close(reinterpret_cast(tcp), on_close); 34 | 35 | delete[] buf->base; 36 | } 37 | 38 | void write2(uv_stream_t* stream, char *data, int len2) 39 | { 40 | uv_buf_t buffer[] = 41 | { 42 | {.base = data, .len = len2} 43 | }; 44 | 45 | uv_write_t *req = new uv_write_t; 46 | uv_write(req, stream, buffer, 1, on_write); 47 | } 48 | 49 | void on_connect(uv_connect_t* connection, int status) 50 | { 51 | if (status < 0) 52 | { 53 | std::cout << "Failed to connect" << std::endl; 54 | return; 55 | } 56 | std::cout << "connected - " << connection << ":" << status << std::endl; 57 | 58 | uv_stream_t* stream = connection->handle; 59 | delete connection; 60 | write2(stream, "echo world!", 12); 61 | uv_read_start(stream, alloc_cb, on_read); 62 | } 63 | 64 | void start_connection(char *host, int port) 65 | { 66 | uv_tcp_t *sock = new uv_tcp_t; 67 | uv_tcp_init(uv_default_loop(), sock); 68 | uv_tcp_keepalive(sock, true, 60); 69 | 70 | sockaddr_in dest; 71 | uv_ip4_addr(host, port, &dest); 72 | 73 | uv_connect_t *conn = new uv_connect_t; 74 | std::cout << "allocated " << conn << std::endl; 75 | uv_tcp_connect(conn, sock, reinterpret_cast(&dest), on_connect); 76 | } 77 | 78 | int main(int argc, char **argv) 79 | {; 80 | int i; 81 | for (i=0; i<10; i++) 82 | start_connection("127.0.0.1", 8080); 83 | 84 | uv_run(uv_default_loop(), UV_RUN_DEFAULT); 85 | } 86 | -------------------------------------------------------------------------------- /Chapter05/example_TCP_server.cpp: -------------------------------------------------------------------------------- 1 | // g++ example_TCP_server.cpp -luv 2 | 3 | #include 4 | #include 5 | 6 | #define PORT 8080 7 | 8 | struct WriteRequest 9 | { 10 | uv_write_t request; 11 | uv_buf_t buffer; 12 | }; 13 | 14 | static uint64_t data_container = 0; 15 | 16 | 17 | static void on_close(uv_handle_t* handle) 18 | { 19 | delete handle; 20 | } 21 | 22 | 23 | static void after_write(uv_write_t* request, int status) 24 | { 25 | WriteRequest* write_request = (WriteRequest*)request; 26 | 27 | if (write_request->buffer.base != NULL) 28 | delete[] write_request->buffer.base; 29 | delete write_request; 30 | 31 | if (status == 0) 32 | return; 33 | 34 | std::cerr << "uv_write error: " << uv_strerror(status) << std::endl; 35 | 36 | if (status == UV_ECANCELED) 37 | return; 38 | 39 | uv_close(reinterpret_cast(request->handle), on_close); 40 | } 41 | 42 | 43 | static void after_shutdown(uv_shutdown_t* request, int status) 44 | { 45 | if (status < 0) 46 | std::cerr << "err: " << uv_strerror(status) << std::endl; 47 | std::cerr << "data received: " << (data_container / 1024 / 1024) << std::endl; 48 | data_container = 0; 49 | uv_close(reinterpret_cast(request->handle), on_close); 50 | delete request; 51 | } 52 | 53 | 54 | static void after_read(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) 55 | { 56 | WriteRequest* write_request; 57 | uv_shutdown_t* request; 58 | 59 | if (nread <= 0 && buf->base != NULL) 60 | delete[] buf->base; 61 | 62 | if (nread == 0) 63 | return; 64 | 65 | if (nread < 0) 66 | { 67 | std::cerr << "err: " << uv_strerror(nread) << std::endl; 68 | request = new uv_shutdown_t; 69 | uv_shutdown(request, handle, after_shutdown); 70 | return; 71 | } 72 | 73 | std::cout << "after_read - " << buf->base << std::endl; 74 | 75 | data_container += nread; 76 | write_request = new WriteRequest; 77 | write_request->buffer = uv_buf_init(buf->base, nread); 78 | uv_write(&write_request->request, handle, &write_request->buffer, 1, after_write); 79 | } 80 | 81 | 82 | static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buffer) 83 | { 84 | buffer->base = new char[suggested_size]; 85 | buffer->len = suggested_size; 86 | } 87 | 88 | 89 | static void on_connection(uv_stream_t* server, int status) 90 | { 91 | uv_tcp_t* stream; 92 | stream = new uv_tcp_t; 93 | uv_tcp_init(uv_default_loop(), stream); 94 | stream->data = server; 95 | uv_accept(server, reinterpret_cast(stream)); 96 | uv_read_start(reinterpret_cast(stream), alloc_cb, after_read); 97 | } 98 | 99 | 100 | static int tcp_echo_server() 101 | { 102 | uv_tcp_t* tcp_server; 103 | sockaddr_in addr; 104 | 105 | uv_ip4_addr("0.0.0.0", PORT, &addr); 106 | tcp_server = new uv_tcp_t; 107 | uv_tcp_init(uv_default_loop(), tcp_server); 108 | uv_tcp_bind(tcp_server, reinterpret_cast(&addr), 0); 109 | uv_listen(reinterpret_cast(tcp_server), SOMAXCONN, on_connection); 110 | 111 | return 0; 112 | } 113 | 114 | 115 | int main() 116 | { 117 | tcp_echo_server(); 118 | 119 | uv_run(uv_default_loop(), UV_RUN_DEFAULT); 120 | 121 | return 0; 122 | } 123 | -------------------------------------------------------------------------------- /Chapter05/example_TCP_server_fullerrorcheck.cpp: -------------------------------------------------------------------------------- 1 | // g++ example_TCP_server_fullerrorcheck.cpp -luv 2 | 3 | #include 4 | #include 5 | 6 | #define PORT 8000 7 | 8 | struct WriteRequest 9 | { 10 | uv_write_t request; 11 | uv_buf_t buffer; 12 | }; 13 | 14 | static uint64_t data_container = 0; 15 | 16 | 17 | static void on_close(uv_handle_t* handle) 18 | { 19 | delete handle; 20 | } 21 | 22 | 23 | static void after_write(uv_write_t* request, int status) 24 | { 25 | WriteRequest* write_request = (WriteRequest*)request; 26 | 27 | if (write_request->buffer.base != NULL) 28 | delete[] write_request->buffer.base; 29 | delete write_request; 30 | 31 | if (status == 0) 32 | return; 33 | 34 | std::cerr << "uv_write error: " <handle, on_close); 41 | } 42 | 43 | 44 | static void after_shutdown(uv_shutdown_t* request, int status) 45 | { 46 | if (status < 0) 47 | std::cerr << "err: " << uv_strerror(status) << std::endl; 48 | std::cerr << "data received: " << (data_container / 1024 / 1024) << std::endl; 49 | data_container = 0; 50 | uv_close((uv_handle_t*)request->handle, on_close); 51 | delete request; 52 | } 53 | 54 | 55 | static void after_read(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) 56 | { 57 | WriteRequest* write_request; 58 | uv_shutdown_t* request; 59 | 60 | if (nread <= 0 && buf->base != NULL) 61 | delete[] buf->base; 62 | 63 | if (nread == 0) 64 | return; 65 | 66 | if (nread < 0) 67 | { 68 | std::cerr << "err: " << uv_strerror(nread) << std::endl; 69 | 70 | request = new uv_shutdown_t; 71 | if (request == NULL) { std::cerr << "new failed" << std::endl; return; } 72 | 73 | int ec = uv_shutdown(request, handle, after_shutdown); 74 | if (ec != 0) { std::cerr << "uv_shutdown failed with value " << ec << std::endl; return; } 75 | 76 | return; 77 | } 78 | 79 | data_container += nread; 80 | 81 | write_request = new WriteRequest; 82 | if (write_request == NULL) { std::cerr << "new failed" << std::endl; return; } 83 | 84 | write_request->buffer = uv_buf_init(buf->base, nread); 85 | 86 | int ec = uv_write(&write_request->request, handle, &write_request->buffer, 1, after_write); 87 | if (ec != 0) { std::cerr << "uv_write failed with value " << ec << std::endl; return; } 88 | } 89 | 90 | 91 | static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buffer) 92 | { 93 | buffer->base = new char[suggested_size]; 94 | if (buffer->base == NULL) { std::cerr << "new failed" << std::endl; return; } 95 | buffer->len = suggested_size; 96 | } 97 | 98 | 99 | static void on_connection(uv_stream_t* server, int status) 100 | { 101 | uv_tcp_t* stream; 102 | 103 | if (status != 0) { std::cerr << "status not OK" << std::endl; return; } 104 | 105 | stream = new uv_tcp_t; 106 | if (stream == NULL) { std::cerr << "new failed" << std::endl; return; } 107 | 108 | int ec = uv_tcp_init(uv_default_loop(), stream); 109 | if (ec != 0) { std::cerr << "uv_tcp_init failed with value " << ec << std::endl; return; } 110 | 111 | stream->data = server; 112 | 113 | ec = uv_accept(server, (uv_stream_t*)stream); 114 | if (ec != 0) { std::cerr << "uv_accept failed with value " << ec << std::endl; return; } 115 | 116 | ec = uv_read_start((uv_stream_t*)stream, alloc_cb, after_read); 117 | if (ec != 0) { std::cerr << "uuv_read_startv_listen failed with value " << ec << std::endl; return; } 118 | } 119 | 120 | 121 | static int tcp_echo_server() 122 | { 123 | uv_tcp_t* tcp_server; 124 | struct sockaddr_in addr; 125 | 126 | int ec = uv_ip4_addr("0.0.0.0", PORT, &addr); 127 | if (ec != 0) { std::cerr << "uv_run failed with value " << ec << std::endl; return ec; } 128 | 129 | tcp_server = new uv_tcp_t; 130 | if (tcp_server == NULL) { std::cerr << "new failed" << std::endl; return 1; } 131 | 132 | ec = uv_tcp_init(uv_default_loop(), tcp_server); 133 | if (ec != 0) { std::cerr << "uv_tcp_init failed with value " << ec << std::endl; return ec; } 134 | 135 | ec = uv_tcp_bind(tcp_server, reinterpret_cast(&addr), 0); 136 | if (ec != 0) { std::cerr << "uv_tcp_bind failed with value " << ec << std::endl; return ec; } 137 | 138 | ec = uv_listen(reinterpret_cast(tcp_server), SOMAXCONN, on_connection); 139 | if (ec != 0) { std::cerr << "uv_listen failed with value " << ec << std::endl; return ec; } 140 | 141 | return 0; 142 | } 143 | 144 | 145 | int main() 146 | { 147 | int ec = tcp_echo_server(); 148 | if (ec != 0) { std::cerr << "tcp_echo_server failed with value " << ec << std::endl; return ec; } 149 | 150 | ec = uv_run(uv_default_loop(), UV_RUN_DEFAULT); 151 | if (ec != 0) { std::cerr << "uv_run failed with value " << ec << std::endl; return ec; } 152 | 153 | return 0; 154 | } 155 | -------------------------------------------------------------------------------- /Chapter05/example_UDP.cpp: -------------------------------------------------------------------------------- 1 | // g++ example_UDP.cpp -luv 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | uv_loop_t *loop; 9 | uv_udp_t send_socket; 10 | uv_udp_t recv_socket; 11 | 12 | void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buffer_out) 13 | { 14 | *buffer_out = uv_buf_init(new char[suggested_size], suggested_size); 15 | } 16 | 17 | void on_read(uv_udp_t *req, ssize_t nread, const uv_buf_t * buf, const sockaddr *addr, unsigned int flags) 18 | { 19 | if (nread == -1) 20 | { 21 | std::cerr << "Read error!" << std::endl; 22 | uv_close(reinterpret_cast(req), NULL); 23 | delete[] buf->base; 24 | return; 25 | } 26 | 27 | char sender[17] = { 0 }; 28 | uv_ip4_name(reinterpret_cast(addr), sender, 16); 29 | std::cerr << "Recv from " << sender << std::endl; 30 | 31 | // DHCP specific code 32 | unsigned int *as_integer = reinterpret_cast(buf->base); 33 | unsigned int ipbin = ntohl(as_integer[4]); 34 | unsigned char ip[4] = {0}; 35 | int i; 36 | for (i = 0; i < 4; i++) 37 | ip[i] = (ipbin >> i*8) & 0xff; 38 | std::cerr << "Offered IP " << ip[3] << "." << ip[2] << "." << ip[1] << "." << ip[0] << std::endl; 39 | 40 | delete[] buf->base; 41 | uv_udp_recv_stop(req); 42 | } 43 | 44 | uv_buf_t make_msg(uv_udp_send_t *req) 45 | { 46 | uv_buf_t buffer; 47 | alloc_buffer(reinterpret_cast(req), 256, &buffer); 48 | memset(buffer.base, 0, buffer.len); 49 | 50 | // ... fill buffer with request 51 | 52 | return buffer; 53 | } 54 | 55 | void on_send(uv_udp_send_t *req, int status) 56 | { 57 | if (status == -1) 58 | { 59 | std::cerr << "Send error!" << std::endl; 60 | return; 61 | } 62 | } 63 | 64 | int main() 65 | { 66 | loop = uv_default_loop(); 67 | 68 | uv_udp_init(loop, &recv_socket); 69 | sockaddr_in recv_addr; 70 | uv_ip4_addr("0.0.0.0", 68, &recv_addr); 71 | uv_udp_bind(&recv_socket, reinterpret_cast(&recv_addr), 0); 72 | uv_udp_recv_start(&recv_socket, alloc_buffer, on_read); 73 | 74 | uv_udp_init(loop, &send_socket); 75 | sockaddr_in bc_addr; 76 | uv_ip4_addr("0.0.0.0", 0, &bc_addr); 77 | uv_udp_bind(&send_socket, reinterpret_cast(&bc_addr), 0); 78 | uv_udp_set_broadcast(&send_socket, true); 79 | 80 | uv_udp_send_t send_req; 81 | uv_buf_t discover_msg = make_msg(&send_req); 82 | 83 | sockaddr_in send_addr; 84 | uv_ip4_addr("255.255.255.255", 67, &send_addr); 85 | uv_udp_send(&send_req, &send_socket, &discover_msg, 1, reinterpret_cast(&send_addr), on_send); 86 | 87 | return uv_run(loop, UV_RUN_DEFAULT); 88 | } 89 | -------------------------------------------------------------------------------- /Chapter06/Makefile: -------------------------------------------------------------------------------- 1 | CC = g++ 2 | CFLAGS = -lnanomsg 3 | 4 | server: example_server.cpp 5 | $(CC) -o $@ $^ $(CFLAGS) 6 | 7 | client: example_client.cpp 8 | $(CC) -o $@ $^ $(CFLAGS) 9 | 10 | 11 | all: server client 12 | 13 | 14 | clean: 15 | rm -f server 16 | rm -f client 17 | 18 | help: 19 | cat ./README 20 | -------------------------------------------------------------------------------- /Chapter06/README: -------------------------------------------------------------------------------- 1 | Prerequisite: nanomsg Library 2 | apt-get install libnanomsg-dev #(on Ubuntu) 3 | 4 | Here are the different command lines to build the examples 5 | 6 | make server 7 | make client 8 | 9 | You also have the possibility to build all, clean and show help 10 | 11 | make all 12 | make clean 13 | make help 14 | 15 | -------------------------------------------------------------------------------- /Chapter06/client: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Network-Programming-with-CPP/e93a2cf3a868b629dc07147c9fa36ed9df770b8b/Chapter06/client -------------------------------------------------------------------------------- /Chapter06/example_client.cpp: -------------------------------------------------------------------------------- 1 | // g++ example_client.cpp -lnanomsg 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | struct Work 14 | { 15 | Work *next; 16 | nn_msghdr request; 17 | uint64_t expire; 18 | void *control; 19 | }; 20 | 21 | uint64_t milliseconds(void) 22 | { 23 | timeval tv; 24 | gettimeofday(&tv, NULL); 25 | return (static_cast(tv.tv_sec * 1000) + static_cast(tv.tv_usec / 1000)); 26 | } 27 | 28 | int client(const std::string & url, unsigned int msec) 29 | { 30 | int fd; 31 | int rc; 32 | char *greeting; 33 | uint8_t msg[sizeof(uint32_t)]; 34 | uint64_t start; 35 | uint64_t end; 36 | 37 | fd = nn_socket(AF_SP, NN_REQ); 38 | if (fd < 0) 39 | { 40 | std::cerr << "nn_socket: " << nn_strerror(nn_errno()) << std::endl; 41 | return 1; 42 | } 43 | 44 | if (nn_connect(fd, url.c_str()) < 0) 45 | { 46 | std::cerr << "nn_socket: " << nn_strerror(nn_errno()) << std::endl; 47 | nn_close(fd); 48 | return 1; 49 | } 50 | 51 | msec = htonl(msec); 52 | memcpy(msg, &msec, sizeof(msec)); 53 | 54 | start = milliseconds(); 55 | 56 | std::cout << "Sending query, expecting a response in " << ntohl(msec) << "ms" << std::endl; 57 | if (nn_send(fd, msg, sizeof(msg), 0) < 0) 58 | { 59 | std::cerr << "nn_send: " << nn_strerror(nn_errno()) << std::endl; 60 | nn_close(fd); 61 | return 1; 62 | } 63 | 64 | rc = nn_recv(fd, &msg, sizeof(msg), 0); 65 | if (rc < 0) 66 | { 67 | std::cerr << "nn_recv: " << nn_strerror(nn_errno()) << std::endl; 68 | nn_close(fd); 69 | return 1; 70 | } 71 | 72 | nn_close(fd); 73 | 74 | end = milliseconds(); 75 | 76 | std::cout << "Request took " << (end - start) << " milliseconds." << std::endl; 77 | return 0; 78 | } 79 | 80 | int main() 81 | { 82 | std::string url = "tcp://127.0.0.1:8080"; 83 | unsigned int msec = 1500; 84 | int rc = client(url, msec); 85 | 86 | return rc; 87 | } 88 | -------------------------------------------------------------------------------- /Chapter06/example_server.cpp: -------------------------------------------------------------------------------- 1 | // g++ example_server.cpp -lnanomsg 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #define MAXJOBS 100 14 | 15 | struct Work 16 | { 17 | Work *next; 18 | nn_msghdr request; 19 | uint64_t expire; 20 | void *control; 21 | }; 22 | 23 | uint64_t milliseconds(void) 24 | { 25 | timeval tv; 26 | gettimeofday(&tv, NULL); 27 | return (static_cast(tv.tv_sec * 1000) + static_cast(tv.tv_usec / 1000)); 28 | } 29 | 30 | int server(const std::string & url) 31 | { 32 | Work *worklist = NULL; 33 | int npending = 0; 34 | 35 | int socket = nn_socket(AF_SP_RAW, NN_REP); 36 | if (socket < 0) 37 | { 38 | std::cout << "nn_socket: " << nn_strerror(nn_errno()) << std::endl; 39 | return 1; 40 | } 41 | 42 | int ec = nn_bind(socket, url.c_str()); 43 | 44 | if (ec < 0) 45 | { 46 | std::cerr << "nn_bind: " << nn_strerror(nn_errno()) << std::endl; 47 | nn_close(socket); 48 | return 1; 49 | } 50 | 51 | while (true) 52 | { 53 | uint32_t timer; 54 | int rc; 55 | int timeout; 56 | uint64_t now; 57 | Work *work; 58 | Work **srch; 59 | uint8_t *body; 60 | void *control; 61 | nn_iovec iov; 62 | nn_msghdr hdr; 63 | nn_pollfd pfd[1]; 64 | 65 | timeout = -1; 66 | while ((work = worklist) != NULL) 67 | { 68 | now = milliseconds(); 69 | if (work->expire > now) { 70 | timeout = (work->expire - now); 71 | break; 72 | } 73 | worklist = work->next; 74 | npending--; 75 | rc = nn_sendmsg(socket, &work->request, NN_DONTWAIT); 76 | if (rc < 0) 77 | { 78 | std::cerr << "nn_sendmsg: " << nn_strerror(nn_errno()) << std::endl; 79 | nn_freemsg(work->request.msg_control); 80 | } 81 | delete work; 82 | } 83 | 84 | if (npending >= MAXJOBS) 85 | { 86 | nn_poll(pfd, 0, timeout); 87 | continue; 88 | } 89 | 90 | pfd[0].fd = socket; 91 | pfd[0].events = NN_POLLIN; 92 | pfd[0].revents = 0; 93 | nn_poll(pfd, 1, timeout); 94 | 95 | if ((pfd[0].revents & NN_POLLIN) == 0) 96 | { 97 | continue; 98 | } 99 | 100 | memset(&hdr, 0, sizeof(hdr)); 101 | control = NULL; 102 | iov.iov_base = &body; 103 | iov.iov_len = NN_MSG; 104 | hdr.msg_iov = &iov; 105 | hdr.msg_iovlen = 1; 106 | hdr.msg_control = &control; 107 | hdr.msg_controllen = NN_MSG; 108 | 109 | rc = nn_recvmsg(socket, &hdr, 0); 110 | if (rc < 0) 111 | { 112 | std::cerr << "nn_recv: " << nn_strerror(nn_errno()) << std::endl; 113 | break; 114 | } 115 | if (rc != sizeof(uint32_t)) 116 | { 117 | std::cerr << "nn_recv: wanted " << sizeof(uint32_t) << ", but got " << rc << std::endl, 118 | nn_freemsg(body); 119 | nn_freemsg(control); 120 | continue; 121 | } 122 | 123 | memcpy(&timer, body, sizeof(timer)); 124 | nn_freemsg(body); 125 | 126 | std::cout << "Received query - sending response in " << ntohl(timer) << "ms" << std::endl ; 127 | work = new Work; 128 | if (work == NULL) 129 | { 130 | std::cerr << "new: " << strerror(errno) << std::endl; 131 | break; 132 | } 133 | memset(work, 0, sizeof(*work)); 134 | work->expire = milliseconds() + ntohl(timer); 135 | work->control = control; 136 | work->request.msg_iovlen = 0; /* No payload data to send. */ 137 | work->request.msg_iov = NULL; 138 | work->request.msg_control = &work->control; 139 | work->request.msg_controllen = NN_MSG; 140 | 141 | srch = &worklist; 142 | while (true) 143 | { 144 | if ((*srch == NULL) || ((*srch)->expire > work->expire)) 145 | { 146 | work->next = *srch; 147 | *srch = work; 148 | npending++; 149 | break; 150 | } 151 | srch = &((*srch)->next); 152 | } 153 | } 154 | 155 | nn_shutdown(socket, ec); 156 | nn_close(socket); 157 | return 1; 158 | } 159 | 160 | 161 | int main() 162 | { 163 | std::string url = "tcp://127.0.0.1:8080"; 164 | int rc = server(url); 165 | 166 | return rc; 167 | } 168 | -------------------------------------------------------------------------------- /Chapter06/server: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Network-Programming-with-CPP/e93a2cf3a868b629dc07147c9fa36ed9df770b8b/Chapter06/server -------------------------------------------------------------------------------- /Chapter07/.gitignore: -------------------------------------------------------------------------------- 1 | client 2 | server 3 | *.backup 4 | *.swp 5 | *.swo 6 | -------------------------------------------------------------------------------- /Chapter07/Makefile: -------------------------------------------------------------------------------- 1 | CC=g++ 2 | CFLAGS=/usr/lib/x86_64-linux-gnu/libACE.so 3 | 4 | all: server client 5 | 6 | 7 | clean: 8 | rm -f client 9 | rm -f server 10 | 11 | 12 | server: server.cpp 13 | $(CC) -o $@ $^ $(CFLAGS) 14 | 15 | client: client.cpp 16 | $(CC) -o $@ $^ $(CFLAGS) 17 | 18 | 19 | -------------------------------------------------------------------------------- /Chapter07/client.cpp: -------------------------------------------------------------------------------- 1 | #include "ace/SOCK_Connector.h" 2 | #include "ace/Log_Msg.h" 3 | 4 | static u_short SERVER_PORT = ACE_DEFAULT_SERVER_PORT; 5 | static const char *const SERVER_HOST = "127.168.0.1"; 6 | static const int MAX_ITERATIONS = 4; 7 | 8 | int 9 | main(int argc, char *argv[]) 10 | { 11 | const char *server_host = argc > 1 ? argv[1] : SERVER_HOST; 12 | u_short server_port = argc > 2 ? ACE_OS::atoi(argv[2]) : SERVER_PORT; 13 | int max_iterations = argc > 3 ? ACE_OS::atoi(argv[3]) : MAX_ITERATIONS; 14 | 15 | ACE_SOCK_Stream server; 16 | 17 | ACE_SOCK_Connector connector; 18 | 19 | ACE_INET_Addr addr(server_port, server_host); 20 | 21 | if (connector.connect(server, addr) == -1) 22 | ACE_ERROR_RETURN((LM_ERROR,"%p\n","open"),-1); 23 | 24 | for (int i = 0; i < max_iterations; i++) 25 | { 26 | char buf[BUFSIZ]; 27 | 28 | ACE_OS::sprintf(buf,"message = %d\n",i + 1); 29 | if (server.send_n(buf,ACE_OS::strlen(buf)) == -1) 30 | ACE_ERROR_RETURN((LM_ERROR,"%p\n","send"),-1); 31 | else 32 | ACE_OS::sleep(1); 33 | } 34 | 35 | if (server.close() == -1) 36 | ACE_ERROR_RETURN((LM_ERROR,"%p\n","close"),-1); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /Chapter07/server.cpp: -------------------------------------------------------------------------------- 1 | #include "ace/SOCK_Acceptor.h" 2 | #include "ace/Event_Handler.h" 3 | #include "ace/Event_Handler.h" 4 | #include "ace/INET_Addr.h" 5 | #include "ace/SOCK_Stream.h" 6 | #include "ace/Log_Msg.h" 7 | #include "ace/Reactor.h" 8 | ACE_Reactor *g_reactor; 9 | 10 | 11 | class Logging_Handler : public ACE_Event_Handler 12 | { 13 | public: 14 | int open(ACE_Reactor *reactor) 15 | { 16 | reactor_ = reactor; 17 | 18 | if (reactor->register_handler(this, ACE_Event_Handler::READ_MASK) == -1) 19 | ACE_ERROR_RETURN((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1); 20 | return 0; 21 | } 22 | 23 | int close(void) 24 | { 25 | return this->handle_close(ACE_INVALID_HANDLE, ACE_Event_Handler::RWE_MASK); 26 | } 27 | 28 | operator ACE_SOCK_Stream &() 29 | { 30 | return this->cli_stream_; 31 | } 32 | 33 | private: 34 | 35 | ACE_HANDLE get_handle(void) const 36 | { 37 | return this->cli_stream_.get_handle(); 38 | } 39 | 40 | 41 | virtual int handle_input(ACE_HANDLE) 42 | { 43 | char buf[BUFSIZ + 1]; 44 | 45 | ssize_t retval; 46 | switch(retval = this->cli_stream_.recv(buf, BUFSIZ)) 47 | { 48 | case -1: 49 | ACE_ERROR_RETURN((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1); 50 | case 0: 51 | ACE_ERROR_RETURN((LM_ERROR, "(%P|%t) closing log daemon(fd = %d)\n", this->get_handle()), -1); 52 | default: 53 | buf[retval] = '\0'; 54 | ACE_DEBUG((LM_DEBUG, "(%P|%t) from client: %s", buf)); 55 | } 56 | 57 | return 0; 58 | } 59 | 60 | int handle_close(ACE_HANDLE, ACE_Reactor_Mask _mask) 61 | { 62 | reactor_->remove_handler(this, _mask | ACE_Event_Handler::DONT_CALL); 63 | cli_stream_.close(); 64 | delete this; 65 | 66 | return 0; 67 | } 68 | 69 | ACE_SOCK_Stream cli_stream_; 70 | ACE_Reactor *reactor_; 71 | }; 72 | 73 | 74 | class Logging_Acceptor : public ACE_Event_Handler 75 | { 76 | public: 77 | int open(const ACE_INET_Addr &addr, ACE_Reactor *reactor) 78 | { 79 | if (this->peer_acceptor_.open(addr, 1) == -1) 80 | return -1; 81 | 82 | reactor_ = reactor; 83 | 84 | return reactor->register_handler(this, ACE_Event_Handler::ACCEPT_MASK); 85 | } 86 | 87 | private: 88 | ACE_HANDLE get_handle(void) const 89 | { 90 | return this->peer_acceptor_.get_handle(); 91 | } 92 | 93 | virtual int handle_input(ACE_HANDLE unused) 94 | { 95 | Logging_Handler *svc_handler; 96 | ACE_NEW_RETURN(svc_handler,Logging_Handler, -1); 97 | 98 | if (this->peer_acceptor_.accept(*svc_handler) == -1) 99 | ACE_ERROR_RETURN((LM_ERROR, "%p", "accept failed"), -1); 100 | 101 | if (svc_handler->open(reactor_) == -1) 102 | svc_handler->close(); 103 | 104 | return 0; 105 | } 106 | 107 | ACE_SOCK_Acceptor peer_acceptor_; 108 | ACE_Reactor *reactor_; 109 | }; 110 | 111 | 112 | static const u_short PORT = ACE_DEFAULT_SERVER_PORT; 113 | 114 | int main(int, char *[]) 115 | { 116 | ACE_Reactor g_reactor; 117 | ACE_INET_Addr addr(PORT); 118 | Logging_Acceptor peer_acceptor; 119 | 120 | if (peer_acceptor.open(addr, &g_reactor) == -1 ) 121 | ACE_ERROR_RETURN((LM_ERROR, "Opening Acceptor\n"),-1); 122 | 123 | ACE_DEBUG((LM_DEBUG,"(%P|%t) starting up server logging daemon\n")); 124 | 125 | while (1) 126 | g_reactor.handle_events(); 127 | 128 | return 0; 129 | } 130 | -------------------------------------------------------------------------------- /Chapter08/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | *.backup 4 | tcp_client 5 | tcp_server 6 | udp_client 7 | udp_server 8 | -------------------------------------------------------------------------------- /Chapter08/Makefile: -------------------------------------------------------------------------------- 1 | CC = g++ 2 | CFLAGS = -isystem -lboost_system 3 | 4 | 5 | tcp_server: example_asio_tcp_server.cpp 6 | $(CC) -o $@ $^ $(CFLAGS) 7 | 8 | tcp_client: example_asio_tcp_client.cpp 9 | $(CC) -o $@ $^ $(CFLAGS) 10 | 11 | tcp: tcp_server tcp_client 12 | 13 | 14 | udp_server: example_asio_udp_server.cpp 15 | $(CC) -o $@ $^ $(CFLAGS) 16 | 17 | 18 | udp_client: example_asio_udp_client.cpp 19 | $(CC) -o $@ $^ $(CFLAGS) 20 | 21 | udp: udp_server udp_client 22 | 23 | 24 | all: tcp_server tcp_client udp_server udp_client 25 | 26 | 27 | clean: 28 | rm -f tcp_server 29 | rm -f tcp_client 30 | rm -f udp_server 31 | rm -f udp_client 32 | 33 | help: 34 | cat ./README 35 | -------------------------------------------------------------------------------- /Chapter08/README: -------------------------------------------------------------------------------- 1 | Prerequisite: Asio Library 2 | apt-get install libasio-dev #(on Ubuntu) 3 | 4 | Here are the different command lines to build the examples 5 | 6 | make tcp_server 7 | make tcp_client 8 | 9 | make udp_server 10 | make udp_client 11 | 12 | You can build all of tcp or udp using these 13 | 14 | make tcp 15 | make udp 16 | 17 | You also have the possibility to build all, clean and show help 18 | 19 | make all 20 | make clean 21 | make help 22 | 23 | -------------------------------------------------------------------------------- /Chapter08/example_asio_tcp_client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | boost::asio::io_service io_service; 7 | 8 | // Socket creation 9 | boost::asio::ip::tcp::socket socket(io_service); 10 | 11 | // Connection 12 | socket.connect( boost::asio::ip::tcp::endpoint( boost::asio::ip::address::from_string("127.0.0.1"), 1234 )); 13 | 14 | // Request/message from client 15 | const std::string msg = "Hello from Client!\n"; 16 | boost::system::error_code error; 17 | boost::asio::write( socket, boost::asio::buffer(msg), error ); 18 | if( !error ) 19 | std::cout << "Client sent hello message!" << std::endl; 20 | else 21 | std::cout << "send failed: " << error.message() << std::endl; 22 | 23 | // Getting response from server 24 | boost::asio::streambuf receive_buffer; 25 | boost::asio::read(socket, receive_buffer, boost::asio::transfer_all(), error); 26 | if( error && error != boost::asio::error::eof ) 27 | { 28 | std::cout << "receive failed: " << error.message() << std::endl; 29 | } 30 | else 31 | { 32 | const char* data = boost::asio::buffer_cast(receive_buffer.data()); 33 | std::cout << data << std::endl; 34 | } 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /Chapter08/example_asio_tcp_server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | boost::asio::io_service io_service; 7 | // Listen for new connection 8 | boost::asio::ip::tcp::acceptor acceptor(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 1234 )); 9 | // Socket creation 10 | boost::asio::ip::tcp::socket socket(io_service); 11 | // Waiting for connection 12 | acceptor.accept(socket); 13 | // Read operation 14 | boost::asio::streambuf buf; 15 | boost::asio::read_until( socket, buf, "\n" ); 16 | std::string message = boost::asio::buffer_cast(buf.data()); 17 | std::cout << message << std::endl; 18 | // Write operation 19 | boost::asio::write( socket, boost::asio::buffer("Hello From Server!") ); 20 | std::cout << "Server sent Hello message to Client!" << std::endl; 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /Chapter08/example_asio_udp_client.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | const size_t MAX_LENGTH = 1024; 9 | 10 | int main() 11 | { 12 | try 13 | { 14 | boost::asio::io_context io_context; 15 | 16 | boost::asio::ip::udp::socket s(io_context, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 0)); 17 | 18 | boost::asio::ip::udp::resolver resolver(io_context); 19 | boost::asio::ip::udp::resolver::results_type endpoints = resolver.resolve(boost::asio::ip::udp::v4(), "127.168.0.1", "1234"); 20 | 21 | char request[] = "Hello world!"; 22 | size_t request_length = std::strlen(request); 23 | s.send_to(boost::asio::buffer(request, request_length), *endpoints.begin()); 24 | std::cout << "Client sent hello message!" << std::endl; 25 | 26 | char reply[MAX_LENGTH]; 27 | boost::asio::ip::udp::endpoint sender_endpoint; 28 | size_t reply_length = s.receive_from(boost::asio::buffer(reply, MAX_LENGTH), sender_endpoint); 29 | std::cout << "Reply is "; 30 | std::cout.write(reply, reply_length); 31 | std::cout << "\n"; 32 | } 33 | catch (std::exception& e) 34 | { 35 | std::cerr << "Exception: " << e.what() << "\n"; 36 | } 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /Chapter08/example_asio_udp_server.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | const size_t MAX_LENGTH = 1024; 8 | 9 | int main() 10 | { 11 | try 12 | { 13 | boost::asio::io_context io_context; 14 | 15 | boost::asio::ip::udp::socket sock(io_context, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 1234)); 16 | 17 | char data[MAX_LENGTH]; 18 | boost::asio::ip::udp::endpoint sender_endpoint; 19 | size_t length = sock.receive_from(boost::asio::buffer(data, MAX_LENGTH), sender_endpoint); 20 | 21 | std::cout << "Client sent "; 22 | std::cout.write(data, length); 23 | std::cout << "\n"; 24 | 25 | sock.send_to(boost::asio::buffer(data, length), sender_endpoint); 26 | 27 | std::cout << "Server sent hello to client!" << std::endl; 28 | } 29 | catch (std::exception& e) 30 | { 31 | std::cerr << "Exception: " << e.what() << "\n"; 32 | } 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /Chapter09/client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char * argv[]) 7 | { 8 | if (argc != 3) 9 | { 10 | std::cout << "Usage: " << argv[0] << " address port" << std::endl; 11 | return 1; 12 | } 13 | 14 | std::string address = argv[1]; 15 | std::string port = argv[2]; 16 | 17 | try 18 | { 19 | std::ostringstream full_url; 20 | full_url << "http://" << address << ":" << port << "/"; 21 | 22 | boost::network::http::client::request request(full_url.str()); 23 | 24 | boost::network::http::client client; 25 | boost::network::http::client::response response = client.get(request); 26 | 27 | std::cout << body(response) << std::endl; 28 | } 29 | catch (std::exception & e) 30 | { 31 | std::cerr << e.what() << std::endl; 32 | return 1; 33 | } 34 | return 0; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /Chapter09/server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | struct HelloWorld; 6 | typedef boost::network::http::server Server; 7 | 8 | struct HelloWorld 9 | { 10 | void operator()(Server::request const &request, Server::connection_ptr connection) 11 | { 12 | Server::string_type ip = source(request); 13 | unsigned int port = request.source_port; 14 | 15 | std::ostringstream data; 16 | data << "Hello, " << ip << ':' << port << '!'; 17 | 18 | connection->set_status(Server::connection::ok); 19 | connection->write(data.str()); 20 | } 21 | }; 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | 26 | if (argc != 3) 27 | { 28 | std::cout << "Usage: " << argv[0] << " address port" << std::endl; 29 | return 1; 30 | } 31 | 32 | std::string address = argv[1]; 33 | std::string port = argv[2]; 34 | 35 | try 36 | { 37 | HelloWorld hw_handler; 38 | Server::options options(hw_handler); 39 | Server server(options.address(address).port(port)); 40 | server.run(); 41 | } 42 | catch (std::exception &e) 43 | { 44 | std::cerr << e.what() << std::endl; 45 | return 1; 46 | } 47 | 48 | return 0; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /Chapter10/Makefile: -------------------------------------------------------------------------------- 1 | CC = g++ 2 | CFLAGS = -fPIC -lQt5Core -lQt5Network -I /usr/include/x86_64-linux-gnu/qt5/ -I /usr/include/x86_64-linux-gnu/qt5/QtCore/ -I /usr/include/x86_64-linux-gnu/qt5/QtNetwork/ 3 | 4 | 5 | tcp_server: example_qt_tcp_server.cpp 6 | $(CC) -o $@ $^ $(CFLAGS) 7 | 8 | tcp_client: example_qt_tcp_client.cpp 9 | $(CC) -o $@ $^ $(CFLAGS) 10 | 11 | tcp: tcp_server tcp_client 12 | 13 | 14 | udp_server: example_qt_udp_server.cpp 15 | $(CC) -o $@ $^ $(CFLAGS) 16 | 17 | udp_client: example_qt_udp_client.cpp 18 | $(CC) -o $@ $^ $(CFLAGS) 19 | 20 | udp: udp_server udp_client 21 | 22 | 23 | all: tcp_server tcp_client udp_server udp_client 24 | 25 | 26 | clean: 27 | rm -f tcp_server 28 | rm -f tcp_client 29 | rm -f udp_server 30 | rm -f udp_client 31 | 32 | help: 33 | cat ./README 34 | -------------------------------------------------------------------------------- /Chapter10/example_qt_tcp_client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | class TCPClient: public QObject 8 | { 9 | public: 10 | TCPClient(); 11 | void start(); 12 | bool alive(); 13 | 14 | public slots: 15 | void onReadyRead(); 16 | 17 | private: 18 | QTcpSocket mSocket; 19 | bool mAlive; 20 | }; 21 | 22 | 23 | TCPClient::TCPClient(): mAlive(true) 24 | { 25 | } 26 | 27 | void TCPClient::start() 28 | { 29 | std::cout << "Connecting..." << std::endl; 30 | mSocket.connectToHost(QHostAddress("127.0.0.1"), 4242); 31 | connect(&mSocket, &QIODevice::readyRead, this, &TCPClient::onReadyRead); 32 | } 33 | 34 | bool TCPClient::alive() 35 | { 36 | return mAlive; 37 | } 38 | 39 | void TCPClient::onReadyRead() 40 | { 41 | // Getting message 42 | QByteArray data = mSocket.readAll(); 43 | std::cout << "Message received: " << data.toStdString() << std::endl; 44 | 45 | // Send response 46 | std::cout << "Sending message back to server..." << std::endl; 47 | mSocket.write(QByteArray("Hello server!\n")); 48 | 49 | // End of connection 50 | mAlive = false; 51 | } 52 | 53 | 54 | int main(int argc, char *argv[]) 55 | { 56 | TCPClient client; 57 | client.start(); 58 | 59 | while (client.alive()) 60 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); 61 | 62 | std::cout << "End of tcp connection" << std::endl; 63 | return 0; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /Chapter10/example_qt_tcp_server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | class TCPServer: public QObject 8 | { 9 | public: 10 | TCPServer(); 11 | void start(); 12 | bool alive(); 13 | 14 | public slots: 15 | void onNewConnection(); 16 | void onReadyRead(); 17 | 18 | private: 19 | QTcpServer mServer; 20 | QList mSockets; 21 | bool mAlive; 22 | }; 23 | 24 | 25 | TCPServer::TCPServer(): mAlive(true) 26 | { 27 | } 28 | 29 | void TCPServer::start() 30 | { 31 | mServer.listen(QHostAddress("127.0.0.1"), 4242); 32 | connect(&mServer, &QTcpServer::newConnection, this, &TCPServer::onNewConnection); 33 | std::cout << "Waiting connection..." << std::endl; 34 | } 35 | 36 | bool TCPServer::alive() 37 | { 38 | return mAlive; 39 | } 40 | 41 | void TCPServer::onNewConnection() 42 | { 43 | QTcpSocket *clientSocket = mServer.nextPendingConnection(); 44 | connect(clientSocket, &QIODevice::readyRead, this, &TCPServer::onReadyRead); 45 | std::cout << "Connected" << std::endl; 46 | 47 | mSockets.push_back(clientSocket); 48 | 49 | // Send message 50 | for (QTcpSocket* socket : mSockets) 51 | { 52 | std::cout << "Sending message to client..." << std::endl; 53 | socket->write(QByteArray("Hello client!\n")); 54 | } 55 | 56 | // After this, expecting response 57 | } 58 | 59 | void TCPServer::onReadyRead() 60 | { 61 | // Getting response 62 | QTcpSocket* sender = static_cast(QObject::sender()); 63 | QByteArray data = sender->readAll(); 64 | std::cout << "Response received: " << data.toStdString() << std::endl; 65 | 66 | // End of connection 67 | mAlive = false; 68 | } 69 | 70 | 71 | int main(int argc, char *argv[]) 72 | { 73 | TCPServer server; 74 | server.start(); 75 | 76 | while (server.alive()) 77 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); 78 | 79 | std::cout << "End of tcp connection" << std::endl; 80 | return 0; 81 | } 82 | 83 | -------------------------------------------------------------------------------- /Chapter10/example_qt_udp_client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | class UDPClient: public QObject 8 | { 9 | public: 10 | UDPClient(); 11 | void start(); 12 | bool alive(); 13 | 14 | public slots: 15 | void onReadyRead(); 16 | 17 | private: 18 | QUdpSocket mSocket; 19 | bool mAlive; 20 | }; 21 | 22 | 23 | UDPClient::UDPClient(): mAlive(true) 24 | { 25 | } 26 | 27 | void UDPClient::start() 28 | { 29 | std::cout << "Connecting..." << std::endl; 30 | mSocket.connectToHost(QHostAddress("127.0.0.1"), 4242); 31 | connect(&mSocket, &QIODevice::readyRead, this, &UDPClient::onReadyRead); 32 | } 33 | 34 | bool UDPClient::alive() 35 | { 36 | return mAlive; 37 | } 38 | 39 | void UDPClient::onReadyRead() 40 | { 41 | // Getting message 42 | QByteArray data = mSocket.readAll(); 43 | std::cout << "Message received: " << data.toStdString() << std::endl; 44 | 45 | // Send response 46 | std::cout << "Sending message back to server..." << std::endl; 47 | mSocket.write(QByteArray("Hello server!\n")); 48 | 49 | // End of connection 50 | mAlive = false; 51 | } 52 | 53 | 54 | int main(int argc, char *argv[]) 55 | { 56 | UDPClient client; 57 | client.start(); 58 | 59 | while (client.alive()) 60 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); 61 | 62 | std::cout << "End of udp connection" << std::endl; 63 | return 0; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /Chapter10/example_qt_udp_server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | class UDPServer: public QObject 7 | { 8 | public: 9 | UDPServer(); 10 | void start(); 11 | bool alive(); 12 | 13 | public slots: 14 | void onNewConnection(); 15 | void onReadyRead(); 16 | 17 | private: 18 | QUdpSocket mServer; 19 | QList mSockets; 20 | bool mAlive; 21 | }; 22 | 23 | 24 | UDPServer::UDPServer(): mAlive(true) 25 | { 26 | } 27 | 28 | void UDPServer::start() 29 | { 30 | mServer.bind(QHostAddress("127.0.0.1"), 4242); 31 | std::cout << "Waiting connection..." << std::endl; 32 | } 33 | 34 | bool UDPServer::alive() 35 | { 36 | return mAlive; 37 | } 38 | 39 | void UDPServer::onNewConnection() 40 | { 41 | QUdpSocket *clientSocket = mServer.nextPendingConnection(); 42 | connect(clientSocket, &QIODevice::readyRead, this, &UDPServer::onReadyRead); 43 | std::cout << "Connected" << std::endl; 44 | 45 | mSockets.push_back(clientSocket); 46 | 47 | // Send message 48 | for (QUdpSocket* socket : mSockets) 49 | { 50 | std::cout << "Sending message to client..." << std::endl; 51 | socket->write(QByteArray("Hello client!\n")); 52 | } 53 | 54 | // After this, expecting response 55 | } 56 | 57 | void UDPServer::onReadyRead() 58 | { 59 | // Getting response 60 | QUdpSocket* sender = static_cast(QObject::sender()); 61 | QByteArray data = sender->readAll(); 62 | std::cout << "Response received: " << data.toStdString() << std::endl; 63 | 64 | // End of connection 65 | mAlive = false; 66 | } 67 | 68 | 69 | int main(int argc, char *argv[]) 70 | { 71 | UDPServer server; 72 | server.start(); 73 | 74 | while (server.alive()) 75 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); 76 | 77 | std::cout << "End of udp connection" << std::endl; 78 | return 0; 79 | } 80 | 81 | -------------------------------------------------------------------------------- /Chapter12/.gitignore: -------------------------------------------------------------------------------- 1 | networking-ts-impl/ 2 | client 3 | server 4 | -------------------------------------------------------------------------------- /Chapter12/Makefile: -------------------------------------------------------------------------------- 1 | CC = g++ 2 | CFLAGS = -Inetworking-ts-impl/include 3 | 4 | server: server.cpp 5 | $(CC) -o $@ $^ $(CFLAGS) 6 | 7 | client: client.cpp 8 | $(CC) -o $@ $^ $(CFLAGS) 9 | 10 | 11 | all: server client 12 | 13 | 14 | clean: 15 | rm -f server 16 | rm -f client 17 | 18 | help: 19 | cat ./README 20 | -------------------------------------------------------------------------------- /Chapter12/client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace net = std::experimental::net; 5 | 6 | int main() 7 | { 8 | net::io_context io_context; 9 | net::ip::tcp::socket socket(io_context); 10 | net::ip::tcp::resolver resolver(io_context); 11 | 12 | try 13 | { 14 | net::connect(socket, resolver.resolve("127.0.0.1", "1234")); 15 | } 16 | catch (std::system_error e) 17 | { 18 | std::cout << "connection failed: " << e.what() << std::endl; 19 | return 1; 20 | } 21 | std::cout << "Client connected!" << std::endl; 22 | 23 | // Request/message from client 24 | const std::string msg = "Hello from Client!\n"; 25 | try 26 | { 27 | net::write( socket, net::buffer(msg) ); 28 | } 29 | catch (std::system_error e) 30 | { 31 | std::cout << "send failed: " << e.what() << std::endl; 32 | return 1; 33 | } 34 | std::cout << "Client sent hello message!" << std::endl; 35 | 36 | // Getting response from server 37 | std::string response; 38 | try 39 | { 40 | net::read(socket, net::buffer(response) ); 41 | } 42 | catch (std::system_error e) 43 | { 44 | std::cout << "receive failed: " << e.what() << std::endl; 45 | return 1; 46 | } 47 | std::cout << "Client received message: " << response << std::endl; 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /Chapter12/server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace net = std::experimental::net; 5 | 6 | int main() 7 | { 8 | net::io_context io_context; 9 | 10 | // Listen for new connection 11 | net::ip::tcp::acceptor acceptor(io_context, net::ip::tcp::endpoint(net::ip::tcp::v4(), 1234)); 12 | // Creating socket & waiting for connection 13 | try 14 | { 15 | net::ip::tcp::socket socket = acceptor.accept(io_context); 16 | // Read operation 17 | std::string request; 18 | try 19 | { 20 | net::read( socket, net::buffer(request) ); 21 | } 22 | catch (std::system_error e) 23 | { 24 | std::cout << "receive failed: " << e.what() << std::endl; 25 | return 1; 26 | } 27 | std::cout << "Server received message: " << request << std::endl; 28 | 29 | // Write back 30 | const std::string msg = "Hello to you too!\n"; 31 | try 32 | { 33 | net::write( socket, net::buffer(msg) ); 34 | } 35 | catch (std::system_error e) 36 | { 37 | std::cout << "send failed: " << e.what() << std::endl; 38 | return 1; 39 | } 40 | std::cout << "Server sent hello back!" << std::endl; 41 | } 42 | catch (std::system_error e) 43 | { 44 | std::cout << "connection failed: " << e.what() << std::endl; 45 | return 1; 46 | } 47 | 48 | return 0; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Network-Programming-with-CPP 2 | Network Programming with CPP by Packt Publishing 3 | --------------------------------------------------------------------------------