How to write a multithreaded server in C (threads, sockets)

แชร์
ฝัง
  • เผยแพร่เมื่อ 9 ก.พ. 2025

ความคิดเห็น •

  • @terigopula
    @terigopula 4 ปีที่แล้ว +25

    Explaining concepts with code is pure gold..! As Linus Torvalds says, "Talk is cheap show me the code".

  • @Runeite51
    @Runeite51 ปีที่แล้ว +27

    most unexpected programming video intro

  • @ajidaniel8818
    @ajidaniel8818 5 ปีที่แล้ว +43

    If you are a teacher , i am sure you will produce a bunch of very good programmers.
    Simple, Clear and Crisp , keep up the good work

    • @JacobSorber
      @JacobSorber  5 ปีที่แล้ว +27

      Thanks. I am a teacher, and producing very good programmers is one of my goals.

  • @eduardonolla9470
    @eduardonolla9470 3 ปีที่แล้ว +3

    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

  • @dhruvandangar8005
    @dhruvandangar8005 2 ปีที่แล้ว +1

    The intro was just lit.
    Rainy season touch my heart.

  • @marshalstewart7776
    @marshalstewart7776 5 ปีที่แล้ว +13

    Been really starting to get into computer science and these videos are always interesting and helpful!

    • @JacobSorber
      @JacobSorber  5 ปีที่แล้ว +3

      Thanks. Glad they're helping.

  • @sushmitagoswami2033
    @sushmitagoswami2033 2 ปีที่แล้ว +3

    Much respect to you sir! Thanks for sharing the knowledge

  • @mahamanebana4410
    @mahamanebana4410 3 ปีที่แล้ว +2

    I'm from Africa. Really appreciate your work

    • @JacobSorber
      @JacobSorber  3 ปีที่แล้ว +1

      Glad I could help. Where in Africa?

  • @anwarpenn
    @anwarpenn ปีที่แล้ว +1

    Thank you so much for sharing! very insightful!

  • @giangdieu7395
    @giangdieu7395 ปีที่แล้ว +1

    super cool tutorial. Thank you so much!

  • @copierofvideos2
    @copierofvideos2 4 ปีที่แล้ว +7

    Man this was great thanks! I always felt like c was a shitty language, but I can see that I just have to get more experience with it

    • @Kotesu
      @Kotesu 3 ปีที่แล้ว +4

      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.

    • @cusematt23
      @cusematt23 ปีที่แล้ว +1

      @@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.

  • @Diddy10443
    @Diddy10443 4 ปีที่แล้ว +9

    2:29 "It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want of a wife..." hahaha

  • @whodaFru4551
    @whodaFru4551 5 ปีที่แล้ว +4

    thats the kind of videos i like. very interesting!

  • @foxred2380
    @foxred2380 3 ปีที่แล้ว +1

    Excellent video, I enjoy explanation.

  • @mohammedzaid6634
    @mohammedzaid6634 4 ปีที่แล้ว +2

    hey jacob i didn't get the error that you did in 5:35 even though my backlog=1 on listen function

  • @gavdev12
    @gavdev12 2 ปีที่แล้ว +1

    Very well done video

  • @RaminPourabbas
    @RaminPourabbas 4 หลายเดือนก่อน

    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?

  • @adityavikram5176
    @adityavikram5176 3 ปีที่แล้ว +1

    Awesome video!!

  • @pikimk6167
    @pikimk6167 ปีที่แล้ว +1

    Hi Jacob, i love your videos and could you do a libuv tutorial? I think it will be a fun topic to watch.

  • @cellularmitosis2
    @cellularmitosis2 5 ปีที่แล้ว +1

    Thank you so much for making these videos!

  • @lordadamson
    @lordadamson 5 ปีที่แล้ว +3

    Awesome stuff Jacob :D

  • @CoderBittu
    @CoderBittu 4 หลายเดือนก่อน

    Creating thread for each connection will affect system functions due to overheads?

  • @nafisehvalizadeh1011
    @nafisehvalizadeh1011 2 ปีที่แล้ว +2

    Hi Jacob, thanks for the tutorial. there is one thing I don't get that is every object (HTTP, image files, ..) request handled by a specific thread?

  • @vishwaspaikra795
    @vishwaspaikra795 2 ปีที่แล้ว +1

    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?

  • @axramar1992
    @axramar1992 8 หลายเดือนก่อน +1

    Hi please do some tutorials on EC200U opencpu .

  • @gurjaschawla1019
    @gurjaschawla1019 ปีที่แล้ว +1

    Hi, I can't find the source code on Patreon . can someone send me . Will be very appreciated , Thanks

  • @juanmamani2110
    @juanmamani2110 2 ปีที่แล้ว +1

    Exactly what I was looking for. Thanks for sharing!
    Which c compiler did you use?

  • @techtechlearn3438
    @techtechlearn3438 2 ปีที่แล้ว +1

    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!!!

  • @karthikp3329
    @karthikp3329 3 ปีที่แล้ว +1

    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.

  • @gaddeshamena6781
    @gaddeshamena6781 4 ปีที่แล้ว +1

    Well said sir😊😊

  • @gamezone4470
    @gamezone4470 4 ปีที่แล้ว +3

    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.

    • @JacobSorber
      @JacobSorber  4 ปีที่แล้ว +1

      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.

  • @Huhnmonster
    @Huhnmonster 5 ปีที่แล้ว +5

    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.

    • @JacobSorber
      @JacobSorber  5 ปีที่แล้ว +7

      Yeah, I think so. I'll put event-driven processing and servers (and epoll/kqueue) on my list for future video.

  • @Елена-й2б7щ
    @Елена-й2б7щ ปีที่แล้ว +1

    How to terminate threads explicit?

  • @akshithbellare7568
    @akshithbellare7568 5 ปีที่แล้ว +3

    Hey I needed help with listening from two ports at the same time.What should I do for it?

    • @JacobSorber
      @JacobSorber  5 ปีที่แล้ว +3

      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.

    • @akshithbellare7568
      @akshithbellare7568 5 ปีที่แล้ว +2

      @@JacobSorber We used select , and our project works :)

  • @lania4334
    @lania4334 4 ปีที่แล้ว +2

    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

    • @JacobSorber
      @JacobSorber  4 ปีที่แล้ว +2

      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.

    • @lania4334
      @lania4334 4 ปีที่แล้ว +1

      @@JacobSorber I know but it is my homework

    • @ayoubazacri7234
      @ayoubazacri7234 3 ปีที่แล้ว +1

      @@lania4334 i have the same homework, could please send it to me , I'll appreciate that.

  • @Teog1992
    @Teog1992 4 ปีที่แล้ว +2

    great videos ! Just wanted to ask , the first implementation of the threat , is essentially a producer/consumer model without a queue ?

    • @JacobSorber
      @JacobSorber  4 ปีที่แล้ว +3

      ...where the producer creates the consumers, yes.

  • @hirenpatel6118
    @hirenpatel6118 4 ปีที่แล้ว +2

    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?

    • @tejastatineni7527
      @tejastatineni7527 2 ปีที่แล้ว +1

      Exactly my doubt. It doesn't make sense to create a pointer just for storing the client_socket and deleting it in the handle_connection method.

  • @Nothing-dq5rx
    @Nothing-dq5rx 2 ปีที่แล้ว +1

    Priority Multithreading tcp please

    • @JacobSorber
      @JacobSorber  2 ปีที่แล้ว +1

      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?

    • @Nothing-dq5rx
      @Nothing-dq5rx 2 ปีที่แล้ว +1

      @@JacobSorber I want some sort of example that prioritise for different threads with timing signal also managing threads for tcp transmission

    • @Nothing-dq5rx
      @Nothing-dq5rx 2 ปีที่แล้ว +1

      Sorry for late reply

    • @Nothing-dq5rx
      @Nothing-dq5rx 2 ปีที่แล้ว

      Multi Process scheduling with time slice between different process and diffrent priorities to different process

  • @meluobote7664
    @meluobote7664 4 ปีที่แล้ว +2

    very beautful code, what your IDE is? Is computer system Linux?

  • @andreykrasnov7851
    @andreykrasnov7851 5 ปีที่แล้ว +1

    Thank you for very good video, Jacob! Is it possible to find somewhere source code you use here?

  • @leokiller123able
    @leokiller123able 3 ปีที่แล้ว +1

    Would it make it faster if we use fork() instead of threads?

    • @JacobSorber
      @JacobSorber  3 ปีที่แล้ว +5

      Probably not. Creating a new process should be more work than creating a new thread.

  • @LinucNerd
    @LinucNerd 5 ปีที่แล้ว +7

    Please do a tutorial about Unicode, pls, I need this :c

    • @JacobSorber
      @JacobSorber  5 ปีที่แล้ว +4

      It's definitely coming. I've been thinking about this topic, but life's busy, and it might take a little while to show up in video form.

  • @enioladare4967
    @enioladare4967 3 ปีที่แล้ว +1

    You were a professor at botho right?

  • @wildchild01
    @wildchild01 4 ปีที่แล้ว +1

    Hi Jacob, can you tell me more about the function "check" that you created? I want to use it in my code too. Thanks!

    • @mohammedzaid6634
      @mohammedzaid6634 4 ปีที่แล้ว +1

      int check(int exp, const char *msg)
      {
      if (exp == SOCKETERROR)
      {
      perror(msg);
      exit(EXIT_FAILURE);
      }
      return exp;
      }

  • @SuperCape
    @SuperCape 5 ปีที่แล้ว +4

    What's gonna happen if you pull a SlowLoris DoS attack on this server?

    • @YashasviGoel
      @YashasviGoel 5 ปีที่แล้ว +2

      Would be interesting to see some modifications to this server in order to handle them.

    • @JacobSorber
      @JacobSorber  5 ปีที่แล้ว +2

      Try it out and see. :)

  • @MaiHappyBanda
    @MaiHappyBanda 2 ปีที่แล้ว +1

    i thought its a vlog

  • @Marblewho
    @Marblewho 4 ปีที่แล้ว +1

    What if the handle connection function takes more than one argument?

    • @JacobSorber
      @JacobSorber  4 ปีที่แล้ว +2

      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.

    • @Marblewho
      @Marblewho 4 ปีที่แล้ว +1

      Jacob Sorber Cool, thank you!

  • @markmanning2921
    @markmanning2921 ปีที่แล้ว +3

    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

  • @ragnarlothbrok367
    @ragnarlothbrok367 2 ปีที่แล้ว +3

    too hard to understand

  • @gaddeshamena6781
    @gaddeshamena6781 4 ปีที่แล้ว +1

    Sir I have aa doubt please can u help me can I send u in mail

    • @JacobSorber
      @JacobSorber  4 ปีที่แล้ว +2

      Hi Gadde. I prefer to keep questions here on TH-cam 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.

    • @gaddeshamena6781
      @gaddeshamena6781 4 ปีที่แล้ว +1

      @@JacobSorber sir actually I want to show u in document sir

    • @gaddeshamena6781
      @gaddeshamena6781 4 ปีที่แล้ว +1

      @@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

    • @gaddeshamena6781
      @gaddeshamena6781 4 ปีที่แล้ว

      #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

    • @gaddeshamena6781
      @gaddeshamena6781 4 ปีที่แล้ว +1

      @@JacobSorber please sir would u solve it it is very urgent sir

  • @foodsweets2728
    @foodsweets2728 4 ปีที่แล้ว +1

    You are too good but too fast, cant really follow.

  • @tw7522
    @tw7522 ปีที่แล้ว +1

    This code is horrible. Seriously, you should take the video down.

    • @RoofusRoof19
      @RoofusRoof19 8 หลายเดือนก่อน +1

      ok send me a better example