scaffold basics of tcp and http sockets, connections, receiving data, sending data

This commit is contained in:
2026-09-20 11:11:09 -07:00
commit 9bea995bf7
2 changed files with 116 additions and 0 deletions
+115
View File
@@ -0,0 +1,115 @@
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char **argv) {
printf("hello world\n");
// http is built on top of tcp
// http/1.0 creates a new tcp connection every request
// for an http server implmentation, we listen for packets in a loop, and group request packets
// then we respond with a response broken down into separate packets (headers, body, etc)
int fd = socket(AF_INET, SOCK_STREAM, 0);
// ?? connect or bind the socket to the address?
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(8080),
.sin_addr = INADDR_ANY,
};
int yes = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
int r = bind(fd, (struct sockaddr *) &addr, sizeof(addr));
if (r == -1) {
printf("ERROR: unable to bind to address\n");
return r;
}
// go ahead and listen for incoming connections
r = listen(fd, 3);
if (r == -1) {
printf("ERROR: unable to use socket to listen for incoming connections\n");
return r;
}
printf("Listening on port 8080\n");
fflush(stdout);
// we loop and do blocking accept calls for incoming connections
while (true) {
// we pass in a sockaddr which is filled with the incoming client's information
struct sockaddr client_addr;
int addr_len = sizeof(client_addr);
int client_fd = accept(fd, &client_addr, (socklen_t *) &addr_len);
if (client_fd == -1) {
printf("ERROR: unable to accept incoming client connection\n");
return -1;
}
// new socket is created for the one client connection
// we can recv from this socket
size_t size = 1000;
char *buf = malloc(size);
// TCP is a byte stream so we need to keep calling recv until an end condition (\r\n). HTTP is the protocol which specifies this, not TCP streams
ssize_t received_bytes = recv(client_fd, buf, size, 0);
if (received_bytes > 0) {
printf("received bytes: %d\n", (int) received_bytes);
printf("%.*s\n", received_bytes, buf);
}
// parse the request
char current_line[1000];
int current_line_char = 0;
for (int i = 0; i < received_bytes; i++) {
printf("%c", buf[i]);
current_line[current_line_char] = buf[i];
current_line_char++;
if (buf[i] == '\n') {
printf("line complete: %.*s\n", current_line_char, current_line);
current_line_char = 0;
}
// TODO: find the path from the first header `GET /bootstrap HTTP/1.1`
// decode the request further
}
fflush(stdout);
free(buf);
const char *response =
"HTTP/1.1 200 OK\r\n"
"Content-Length: 5\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n"
"\r\n"
"hello";
r = send(client_fd, response, strlen(response), 0);
if (r == -1) {
printf("ERROR: in sending response");
fflush(stdout);
}
printf("sent %zd of %zu bytes\n", r, strlen(response));
fflush(stdout);
close(client_fd);
}
// TODO: scaffolding
// keep track of multiple requests, examine the request data
// decode the request data
// then respond with particular html page
// close socket
close(fd);
// for an http client library, we need to create a tcp connection, send headers, and then body and other parts of the request in a structure that follows the protocol RFC
}