patterncMinor
Scalability of C server implementation based on pthreads
Viewed 0 times
scalabilitypthreadsbasedserverimplementation
Problem
I am wondering about the feasibility of the following basic implementation of a server and how well it would scale. I know that large-scale, distributed servers should probably be written in a language like Erlang, but I'm interested in the viability of the following code "these days".
Other than bugs/issues I'd primarily like to know 3 things:
```
// SimpleCServer.c
// Adapted from http://beej.us/guide/bgnet/output/print/bgnet_A4.pdf
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// The port users will be connecting to
#define PORT "12345"
// Prototype for processing function
void processRequest(void sdPtr);
// Get sockaddr, IPv4 or IPv6
void get_in_addr(struct sockaddr sa) {
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int argc, char *argv[]) {
// Basic server variables
int sockfd = -1; // Listen on sock_fd
int new_fd; // New connection on new_fd
int yes=1;
int rv;
struct addrinfo hints, servinfo, p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
char s[INET6_ADDRSTRLEN];
// pthread variables
pthread_t workerThread; // Worker thread
pthread_attr_t threadAttr; // Set up detached thread attributes
pthread_attr_init(&threadAttr);
pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
// Server hints
memset(&hints, 0, s
Other than bugs/issues I'd primarily like to know 3 things:
- C headers have many with compatibility methods/structs/etc. Some of which do similar things. Is this a correct "modern" way to handle incoming IPv4 and IPv6 connections?
- How scalable is it? If I have a single VPN and don't need a distributed server, is it adequate for todays applications? (Potentially thousands/millions of concurrent connections? I appreciate the latter would also very much be hardware dependent!)
```
// SimpleCServer.c
// Adapted from http://beej.us/guide/bgnet/output/print/bgnet_A4.pdf
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// The port users will be connecting to
#define PORT "12345"
// Prototype for processing function
void processRequest(void sdPtr);
// Get sockaddr, IPv4 or IPv6
void get_in_addr(struct sockaddr sa) {
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int argc, char *argv[]) {
// Basic server variables
int sockfd = -1; // Listen on sock_fd
int new_fd; // New connection on new_fd
int yes=1;
int rv;
struct addrinfo hints, servinfo, p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
char s[INET6_ADDRSTRLEN];
// pthread variables
pthread_t workerThread; // Worker thread
pthread_attr_t threadAttr; // Set up detached thread attributes
pthread_attr_init(&threadAttr);
pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
// Server hints
memset(&hints, 0, s
Solution
First of all, each connection consumes a local port. Therefore, the number of concurrent connection is hard limited by unsigned short, that is 65536 (so millions are out of question). There are also other limitations you may or may not care about.
Second, thread creation is somewhat expensive. Consider pre-allocating a thread pool.
Third, a code for reading data from the connection is missing. I assume that the intention is for each thread to issue a
Finally, a code review. Your
Second, thread creation is somewhat expensive. Consider pre-allocating a thread pool.
Third, a code for reading data from the connection is missing. I assume that the intention is for each thread to issue a
recv system call. This may lead to many thousands outstanding system calls, each consuming kernel resources. Using poll is way more scalable.Finally, a code review. Your
main does way too much. Variables are declared too far away from their uses. Consider restructuring. At least 2 functions (setup_listener_socket and mainloop) must be realized.Context
StackExchange Code Review Q#53871, answer score: 3
Revisions (0)
No revisions yet.