how common is it for a server to rip the rug out from under every connection just because one request from the client has been acted on. I dont think this is a very good example, it is next to useless for an actual real life purpose
I have been trying to get my threads running for 3 whole days. After using your method of passing the sockets as pointers my problem was solved. Thank you so much
you are a fantastic, thank you very much ..... I have a question, I don't know if you can help me but I want to know how to create multiple processes that connect to the apache web server, establish a connection and keep it waiting, just wait for the server timeout , and when the connection is lost, the process should restart it. In the end what I want is to see the simultaneous connections the web server can support, using a C language and fork () processes, the parent process will count how many processes achieve controls and many don't.
You're welcome. It sounds like an interesting experiment. I'm not sure from the comment what sort of help you're looking for, but I'd love to hear how things go.
It's definitely not for every application, but it is often indispensable for many subdisciplines like kernels, embedded systems, scientific computing, games and other high-performance systems. It's a tricky language if you're coming from a pure compsci background: for most people C is as close to the silicon as they will ever get., and going any closer usually requires assembly. Coding in C requires a lot of patience and discipline but the payoff in performance, memory footprint and overall control of your processor can be well worth the effort.
@@Kotesu very well said. It's actually too bad your comment was buried in a reply because I think a lot of new programmer's would have an "ah ha" moment reading it.
is it a good idea to give each client a thread? is it dangerous? Is it a good idea to handle client request with accept or epoll and assign a thread for a specific task? which is better?
how many cores/threads does your "server" (which I presume it's the actual host pc you are using) have, just so that I can image how many threads can actually run in parallel at once? Thank you!!!
thanks for the tutorial, that's very awesome. I have one question, in this tutorial, do we have thread-safety problem? every thread created is working on a same function with the same resource! if there is such an issue, why the code is running without problem?
Hello Jacob, thank you very much for your content. Would it be possible that you go over evented web servers some day? I would like to get your take on event loops and maybe even a small introduction to select or epoll/kqueue.
Please correct me if I am wrong: If there is pointer to a dynamically allocated memory in calling function and it is passed as an argument to called function (as you did in the case of handleConnection() function), will it not cause a dangling pointer in calling function if the memory is freed in called function? I think it's better to free the memory in calling function (or parent thread) and to be safer, after child thread joining. I guess the pointer in new thread function will have no effect once the function returns and frame is removed from function call stack.
Hi Jacob, confused as to why the value of client_socket is being copied to the heap? When the while loop starts again, shouldn't the new accept call return a different file descriptor than the last iteration? If we pass the file descriptor by value vs by reference we should be fine right?
Can you help me How make this code when we have multiple clients just one client connect that server and the other clients wait for response's server until that client is completed
This server should be able to handle multiple clients. It handles each connection in a separate thread, so as long as your connection handling can be done concurrently, then connections shouldn't have to wait.
Meaning that you would like me to prioritize multithreading TCP, or that you want some sort of example where you prioritize different threads managing TCP connections?
You could use two listening threads, one listening on each port. You could use select (maybe a good topic for a future video). You could also make the sockets nonblocking.
A thread function only takes one argument (void*). One way to do it would be to create a struct with all the things you want to pass in, and then pass a pointer to that struct.
Hi Gadde. I prefer to keep questions here on RU-vid both so they can help more people, but also because I don't always have time to answer them all. If the questions are posted publically, often someone can answer it before I get to it. Of course, I do provide more one-on-one interaction through Patreon.
@@JacobSorber Develop a basic multithreaded webserver (where multiple threads process multiple client requests simultaneously) with support for different scheduling policies for the client requests....this is the question sir but we have to write in given template
#include "io_helper.h" #include "request.h" #define MAXBUF (8192) // // TODO: add code to create and manage the buffer // // // Sends out HTTP response in case of errors // void request_error(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg) { char buf[MAXBUF], body[MAXBUF]; // Create the body of error message first (have to know its length for header) sprintf(body, "" " " " " " OSTEP WebServer Error " " " " " " %s: %s " " %s: %s " " " " ", errnum, shortmsg, longmsg, cause); // Write out the header information for this response sprintf(buf, "HTTP/1.0 %s %s ", errnum, shortmsg); write_or_die(fd, buf, strlen(buf)); sprintf(buf, "Content-Type: text/html "); write_or_die(fd, buf, strlen(buf)); sprintf(buf, "Content-Length: %lu ", strlen(body)); write_or_die(fd, buf, strlen(buf)); // Write out the body last write_or_die(fd, body, strlen(body)); // close the socket connection close_or_die(fd); } // // Reads and discards everything up to an empty text line // void request_read_headers(int fd) { char buf[MAXBUF]; readline_or_die(fd, buf, MAXBUF); while (strcmp(buf, " ")) { readline_or_die(fd, buf, MAXBUF); } return; } // // Return 1 if static, 0 if dynamic content (executable file) // Calculates filename (and cgiargs, for dynamic) from uri // int request_parse_uri(char *uri, char *filename, char *cgiargs) { char *ptr; if (!strstr(uri, "cgi")) { // static strcpy(cgiargs, ""); sprintf(filename, ".%s", uri); if (uri[strlen(uri)-1] == '/') { strcat(filename, "index.html"); } return 1; } else { // dynamic ptr = index(uri, '?'); if (ptr) { strcpy(cgiargs, ptr+1); *ptr = '\0'; } else { strcpy(cgiargs, ""); } sprintf(filename, ".%s", uri); return 0; } } // // Fills in the filetype given the filename // void request_get_filetype(char *filename, char *filetype) { if (strstr(filename, ".html")) strcpy(filetype, "text/html"); else if (strstr(filename, ".gif")) strcpy(filetype, "image/gif"); else if (strstr(filename, ".jpg")) strcpy(filetype, "image/jpeg"); else strcpy(filetype, "text/plain"); } // // Handles requests for static content // void request_serve_static(int fd, char *filename, int filesize) { int srcfd; char *srcp, filetype[MAXBUF], buf[MAXBUF]; request_get_filetype(filename, filetype); srcfd = open_or_die(filename, O_RDONLY, 0); // Rather than call read() to read the file into memory, // which would require that we allocate a buffer, we memory-map the file srcp = mmap_or_die(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0); close_or_die(srcfd); // put together response sprintf(buf, "" "HTTP/1.0 200 OK " "Server: OSTEP WebServer " "Content-Length: %d " "Content-Type: %s ", filesize, filetype); write_or_die(fd, buf, strlen(buf)); // Writes out to the client socket the memory-mapped file write_or_die(fd, srcp, filesize); munmap_or_die(srcp, filesize); } // // Fetches the requests from the buffer and handles them (thread locic) // void* thread_request_serve_static(void* arg) { // TODO: write code to actualy respond to HTTP requests } // // Initial handling of the request // void request_handle(int fd) { int is_static; struct stat sbuf; char buf[MAXBUF], method[MAXBUF], uri[MAXBUF], version[MAXBUF]; char filename[MAXBUF], cgiargs[MAXBUF]; // get the request type, file path and HTTP version readline_or_die(fd, buf, MAXBUF); sscanf(buf, "%s %s %s", method, uri, version); printf("method:%s uri:%s version:%s ", method, uri, version); // verify if the request type is GET is not if (strcasecmp(method, "GET")) { request_error(fd, method, "501", "Not Implemented", "server does not implement this method"); return; } request_read_headers(fd); // check requested content type (static/dynamic) is_static = request_parse_uri(uri, filename, cgiargs); // get some data regarding the requested file, also check if requested file is present on server if (stat(filename, &sbuf) < 0) { request_error(fd, filename, "404", "Not found", "server could not find this file"); return; } // verify if requested content is static if (is_static) { if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) { request_error(fd, filename, "403", "Forbidden", "server could not read this file"); return; } // TODO: write code to add HTTP requests in the buffer based on the scheduling policy } else {.. We have to write in this format sir