-
Notifications
You must be signed in to change notification settings - Fork 0
Development_Environment
Use NGINX as a web server to test behaviour and compare with the program because there are both in HTTP 1.1.
You can use the following command to start an NGINX server in a Docker container:
docker run --rm -d -p 8080:80 --name nginx nginxThis command will start an NGINX server on port 8080. You can then access the server by visiting http://localhost:8080 in your web browser.
- 🥧 HTTPie - WebApp to make HTTP request - Great UI
- Browser
- Postman
- Curl
You can use the curl command to send an HTTP request to the NGINX server. For example, to send a GET request to the server, you can use the following command:
curl http://localhost:8080You can add headers to the request using the -H flag. For example, to send a GET request with a custom User-Agent header, you can use the following command:
curl -H "host: example.com" http://localhost:8080All in CPP98 standard library. (no boost)
| Function | Prototype | Description | Example |
|---|---|---|---|
| execve |
int execve(
const char *filename,
char *const argv[],
char *const envp[]); |
Executes the program pointed to by filename. |
char *args[] = {"/bin/ls", "-l", NULL};
execve(args[0], args, NULL); |
| dup |
int dup(int oldfd); |
Creates a copy of the file descriptor oldfd. |
int newfd = dup(oldfd); |
| dup2 |
int dup2(
int oldfd,
int newfd); |
Makes newfd be the copy of oldfd, closing newfd first if necessary. |
dup2(oldfd, newfd); |
| close |
int close(int fd); |
Closes the file descriptor fd. |
close(fd); |
| fork |
pid_t fork(void); |
Creates a new process by duplicating the calling process. |
pid_t pid = fork(); |
| waitpid |
pid_t waitpid(
pid_t pid,
int *status,
int options); |
Waits for a specific child process to terminate. |
int status;
pid_t pid = waitpid(child_pid, &status, 0); |
| wait |
pid_t wait(int *status); |
Waits for any child process to terminate. |
int status;
pid_t pid = wait(&status); |
| signal |
void (
*signal(
int signum,
void (*handler)(int))
)(int); |
Assigns a signal handler to a signal. |
void handler(int signum) {
// Handle signal
}
signal(SIGINT, handler); |
| kill |
int kill(
pid_t pid,
int sig); |
Sends a signal to a process. |
kill(pid, SIGKILL); |
| socket |
int socket(
int domain,
int type,
int protocol); |
Creates an endpoint for communication. |
int sockfd = socket(AF_INET, SOCK_STREAM, 0); |
| bind |
int bind(
int sockfd,
const struct sockaddr *addr,
socklen_t addrlen); |
Assigns an address to a socket. |
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8080);
addr.sin_addr.s_addr = INADDR_ANY;
bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)); |
| listen |
int listen(
int sockfd,
int backlog); |
Marks a socket as passive, allowing it to accept incoming connections. |
listen(sockfd, 10); |
| accept |
int accept(
int sockfd,
struct sockaddr *addr,
socklen_t *addrlen); |
Accepts a new incoming connection on a socket. |
int newsockfd = accept(sockfd, NULL, NULL); |
| connect |
int connect(
int sockfd,
const struct sockaddr *addr,
socklen_t addrlen); |
Initiates a connection on a socket. |
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080); // Port number
inet_pton(AF_INET, "127.0.0.1", &(serv_addr.sin_addr)); // Server IP address
connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); |
| send |
ssize_t send(
int sockfd,
const void *buf,
size_t len,
int flags); |
Sends data on a connected socket. |
send(sockfd, "Hello, world!", 13, 0); |
| recv |
ssize_t recv(
int sockfd,
void *buf,
size_t len,
int flags); |
Receives data from a connected socket. |
char buffer[1024];
recv(sockfd, buffer, 1024, 0); |
| select |
int select(
int nfds,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
struct timeval *timeout); |
Waits for one of a set of file descriptors to become ready to perform I/O. |
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sockfd, &readfds);
select(sockfd + 1, &readfds, NULL, NULL, NULL); |
| poll |
int poll(
struct pollfd *fds,
nfds_t nfds,
int timeout); |
Waits for one of a set of file descriptors to become ready to perform I/O. |
struct pollfd fds;
fds.fd = sockfd;
fds.events = POLLIN;
poll(&fds, 1, -1); |
| getaddrinfo |
int getaddrinfo(
const char *node,
const char *service,
const struct addrinfo *hints,
struct addrinfo **res); |
Resolves a host name and service name to a set of socket addresses. |
struct addrinfo hints, *res;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
getaddrinfo("www.example.com", "http", &hints, &res); |
| freeaddrinfo |
void freeaddrinfo(struct addrinfo *res); |
Frees the memory allocated for a linked list of addrinfo structures. |
freeaddrinfo(res); |
| htons |
uint16_t htons(uint16_t hostshort); |
Converts a 16-bit hostshort from host byte order to network byte order. |
uint16_t port = 8080;
uint16_t network_port = htons(port); |
| htonl |
uint32_t htonl(uint32_t hostlong); |
Converts a 32-bit hostlong from host byte order to network byte order. |
uint32_t address = 0x7F000001; //
uint32_t network_address = htonl(address); |
| epoll_create |
int epoll_create(int size); |
Creates an epoll instance. |
int epfd = epoll_create(1); |
| epoll_ctl |
int epoll_ctl(
int epfd,
int op,
int fd,
struct epoll_event *event); |
Controls an epoll instance. |
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = sockfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event); |
| epoll_wait |
int epoll_wait(
int epfd,
struct epoll_event *events,
int maxevents,
int timeout); |
Waits for events on an epoll instance. |
struct epoll_event events[10];
int n = epoll_wait(epfd, events, 10, -1); |
... and more.
The poll() and select() functions are used to monitor multiple file descriptors, waiting until one or more of the file descriptors become ready for I/O operations. Here's a brief explanation of each function:
-
poll(): The
poll()function waits for one of a set of file descriptors to become ready to perform I/O. It is similar toselect(), but it provides more flexibility and is more efficient for large numbers of file descriptors. Thepoll()function is available on most Unix-like operating systems. -
select(): The
select()function waits for one of a set of file descriptors to become ready to perform I/O. It is commonly used in network programming to monitor multiple sockets for read/write events. Theselect()function is available on most Unix-like operating systems.
Both functions allow you to specify a timeout value, so you can wait for a certain amount of time before returning if no file descriptors become ready. They also allow you to specify sets of file descriptors to monitor for read, write, and error events.
The epoll API is a more scalable and efficient mechanism for monitoring multiple file descriptors in Unix-like operating systems. It provides better performance than poll() and select() for large numbers of file descriptors. Here's a brief explanation of the epoll API:
-
epoll_create(): The
epoll_create()function creates an epoll instance, which is used to monitor file descriptors for I/O events. -
epoll_ctl(): The
epoll_ctl()function controls an epoll instance, allowing you to add, modify, or remove file descriptors from the set of monitored descriptors. -
epoll_wait(): The
epoll_wait()function waits for events on an epoll instance, returning information about the file descriptors that are ready for I/O operations.
The FD_SET, FD_CLR, FD_ISSET, and FD_ZERO macros are essential tools for working with the select() function in Unix-like operating systems. They operate on fd_set structures, which are used to track the readiness of file descriptors for various I/O operations. Here's a brief explanation of each macro:
| Macro | Prototype | Description |
|---|---|---|
| FD_SET |
void FD_SET(int fd, fd_set *set); |
Adds the file descriptor fd to the set set. It marks the file descriptor as ready for the operation specified in the |
| FD_CLR |
void FD_CLR(int fd, fd_set *set); |
Removes the file descriptor fd from the set set. It clears the mark indicating readiness for the specified operation. This is useful when you want to stop monitoring a particular file descriptor. |
| FD_ISSET |
int FD_ISSET(int fd, fd_set *set); |
Checks if a given file descriptor is part of a file descriptor set. It returns a non-zero value if the file descriptor is marked as ready for the specified operation, and 0 otherwise. This is used after calling select() to determine which file descriptors are now ready for the requested operation. |
| FD_ZERO |
void FD_ZERO(fd_set *set); |
Initializes a file descriptor set to have zero bits for all file descriptors. It effectively clears all previously added file descriptors from the set. This is usually called before adding specific file descriptors to the set using |
These macros are part of the mechanism that allows select() to monitor multiple file descriptors simultaneously, waiting for them to become ready for reading, writing, or having an error condition. By manipulating these sets, you can dynamically control which file descriptors select() should consider.