Update.
This commit is contained in:
parent
fc05199a76
commit
ded2448ebd
21
README.md
21
README.md
@ -155,13 +155,25 @@ int main() {
|
|||||||
### HTTP Server Examples
|
### HTTP Server Examples
|
||||||
|
|
||||||
**Simple HTTP Server** (`examples/http_simple.rc`)
|
**Simple HTTP Server** (`examples/http_simple.rc`)
|
||||||
Single-connection HTTP server that accepts one request and exits.
|
Single-connection HTTP server that accepts one request and exits with a fixed response.
|
||||||
|
|
||||||
**Persistent HTTP Server** (`examples/http_persistent.rc`)
|
**Persistent HTTP Server** (`examples/http_persistent.rc`)
|
||||||
HTTP server with request counter that continuously accepts connections.
|
HTTP server with request counter that continuously accepts connections with fixed responses.
|
||||||
|
|
||||||
**Multi-Connection HTTP Server** (`examples/http_multi.rc`)
|
**HTTP File Server** (`examples/http_fileserver.rc`)
|
||||||
HTTP server that handles up to 100 consecutive connections.
|
HTTP server that serves files from the filesystem. Handles up to 100 connections and streams file content using proper HTTP responses. Demonstrates socket programming, file I/O, and HTTP protocol implementation within RC's type system constraints.
|
||||||
|
|
||||||
|
Run examples:
|
||||||
|
```bash
|
||||||
|
make run-http-simple # Simple single-connection server
|
||||||
|
make run-http-persistent # Persistent multi-connection server
|
||||||
|
./bin/rc examples/http_fileserver.rc # File serving server
|
||||||
|
```
|
||||||
|
|
||||||
|
Test with curl or browser:
|
||||||
|
```bash
|
||||||
|
curl http://localhost:8080/
|
||||||
|
```
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
@ -250,6 +262,7 @@ For technical details, see:
|
|||||||
- Pointer arithmetic works on virtual memory addresses
|
- Pointer arithmetic works on virtual memory addresses
|
||||||
- Maximum 100 concurrent async operations
|
- Maximum 100 concurrent async operations
|
||||||
- Async execution is serialized (not parallel)
|
- Async execution is serialized (not parallel)
|
||||||
|
- **Type system constraints**: String functions (substr, strpos, strcmp) work with string pointers (`char*`) but not with char arrays used as buffers for socket operations
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
|
|||||||
176
TUTORIAL.md
176
TUTORIAL.md
@ -868,6 +868,182 @@ close(sockfd);
|
|||||||
- `AF_INET()` - IPv4 address family
|
- `AF_INET()` - IPv4 address family
|
||||||
- `SOCK_STREAM()` - TCP socket type
|
- `SOCK_STREAM()` - TCP socket type
|
||||||
|
|
||||||
|
### Building an HTTP File Server
|
||||||
|
|
||||||
|
This section demonstrates how to build a complete HTTP file server in RC. The example shows proper socket handling, file I/O, and HTTP response generation.
|
||||||
|
|
||||||
|
#### Complete HTTP File Server Example
|
||||||
|
|
||||||
|
```c
|
||||||
|
int main() {
|
||||||
|
int server_fd;
|
||||||
|
int client_fd;
|
||||||
|
char buffer[4096];
|
||||||
|
int bytes_received;
|
||||||
|
int file;
|
||||||
|
char *line;
|
||||||
|
int line_len;
|
||||||
|
char *response_header;
|
||||||
|
int header_len;
|
||||||
|
int total_sent;
|
||||||
|
int count;
|
||||||
|
char *filename;
|
||||||
|
|
||||||
|
server_fd = socket(AF_INET(), SOCK_STREAM(), 0);
|
||||||
|
if (server_fd < 0) {
|
||||||
|
printf("Failed to create socket\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind(server_fd, 8080) < 0) {
|
||||||
|
printf("Failed to bind to port 8080\n");
|
||||||
|
close(server_fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(server_fd, 10) < 0) {
|
||||||
|
printf("Failed to listen\n");
|
||||||
|
close(server_fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("HTTP File Server listening on port 8080\n");
|
||||||
|
printf("Serving README.md for all requests\n");
|
||||||
|
printf("Example: http://localhost:8080/\n\n");
|
||||||
|
|
||||||
|
filename = "README.md";
|
||||||
|
count = 0;
|
||||||
|
while (count < 100) {
|
||||||
|
printf("Waiting for connection %d\n", count + 1);
|
||||||
|
client_fd = accept(server_fd);
|
||||||
|
|
||||||
|
if (client_fd < 0) {
|
||||||
|
printf("Failed to accept connection\n");
|
||||||
|
count = count + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Client connected\n");
|
||||||
|
|
||||||
|
bytes_received = recv(client_fd, buffer, 1024, 0);
|
||||||
|
if (bytes_received <= 0) {
|
||||||
|
printf("Failed to receive request\n");
|
||||||
|
close(client_fd);
|
||||||
|
count = count + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Received %d bytes\n", bytes_received);
|
||||||
|
|
||||||
|
file = fopen(filename, "r");
|
||||||
|
|
||||||
|
if (file == 0) {
|
||||||
|
printf("File not found: %s\n", filename);
|
||||||
|
response_header = "HTTP/1.1 404 Not Found\nContent-Type: text/html\n\n<html><body><h1>404 Not Found</h1><p>The requested file was not found.</p></body></html>";
|
||||||
|
header_len = strlen(response_header);
|
||||||
|
send(client_fd, response_header, header_len, 0);
|
||||||
|
close(client_fd);
|
||||||
|
count = count + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("File opened successfully\n");
|
||||||
|
|
||||||
|
response_header = "HTTP/1.1 200 OK\nContent-Type: text/plain\n\n";
|
||||||
|
header_len = strlen(response_header);
|
||||||
|
send(client_fd, response_header, header_len, 0);
|
||||||
|
|
||||||
|
total_sent = 0;
|
||||||
|
while (feof(file) == 0) {
|
||||||
|
line = fgets(file, 8192);
|
||||||
|
line_len = strlen(line);
|
||||||
|
if (line_len > 0) {
|
||||||
|
send(client_fd, line, line_len, 0);
|
||||||
|
total_sent = total_sent + line_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Sent %d bytes\n", total_sent);
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
close(client_fd);
|
||||||
|
printf("Connection closed\n\n");
|
||||||
|
|
||||||
|
count = count + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(server_fd);
|
||||||
|
printf("Server shutdown after %d requests\n", count);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Key Concepts
|
||||||
|
|
||||||
|
**Socket Creation and Binding:**
|
||||||
|
The server creates a TCP socket, binds it to port 8080, and listens for incoming connections.
|
||||||
|
|
||||||
|
**Request Loop:**
|
||||||
|
The server runs a loop accepting up to 100 connections. For each connection:
|
||||||
|
1. Accept the client connection
|
||||||
|
2. Receive the HTTP request
|
||||||
|
3. Open the requested file
|
||||||
|
4. Send HTTP response headers
|
||||||
|
5. Send file content line by line
|
||||||
|
6. Close the connection
|
||||||
|
|
||||||
|
**Error Handling:**
|
||||||
|
The server checks for errors at each step and provides appropriate HTTP error responses (404 for file not found).
|
||||||
|
|
||||||
|
**Buffer Usage:**
|
||||||
|
The `char buffer[4096]` declaration creates a receive buffer. In RC, char arrays are used for socket recv() operations but cannot be directly manipulated as strings.
|
||||||
|
|
||||||
|
**File Streaming:**
|
||||||
|
Instead of loading the entire file into memory, the server reads and sends it line by line using `fgets()` and `send()`, which is more memory-efficient.
|
||||||
|
|
||||||
|
#### Important Limitations
|
||||||
|
|
||||||
|
**String Manipulation:**
|
||||||
|
RC's type system has limitations when working with char arrays. Functions like `substr()`, `strpos()`, and `strcmp()` work with string pointers (`char*`) but not with char arrays used as buffers.
|
||||||
|
|
||||||
|
**Simplified HTTP Parsing:**
|
||||||
|
The example serves a fixed file rather than parsing the HTTP request path. Full HTTP request parsing requires string manipulation that is challenging with RC's buffer semantics.
|
||||||
|
|
||||||
|
**Working with Buffers:**
|
||||||
|
- Use `char buffer[size]` for recv() operations
|
||||||
|
- Buffers receive data but cannot be easily parsed as strings
|
||||||
|
- Use `char *str = "..."` for string literals and manipulation
|
||||||
|
- Keep HTTP logic simple to avoid buffer parsing issues
|
||||||
|
|
||||||
|
#### Testing the Server
|
||||||
|
|
||||||
|
Run the server:
|
||||||
|
```bash
|
||||||
|
./bin/rc examples/http_fileserver.rc
|
||||||
|
```
|
||||||
|
|
||||||
|
Test with curl:
|
||||||
|
```bash
|
||||||
|
curl http://localhost:8080/
|
||||||
|
```
|
||||||
|
|
||||||
|
Test with a browser:
|
||||||
|
```
|
||||||
|
http://localhost:8080/
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Production Considerations
|
||||||
|
|
||||||
|
For production HTTP servers:
|
||||||
|
1. Add request timeout handling
|
||||||
|
2. Implement proper HTTP request parsing (in a more suitable language)
|
||||||
|
3. Add support for multiple file types and MIME types
|
||||||
|
4. Implement connection pooling for better performance
|
||||||
|
5. Add logging for debugging and monitoring
|
||||||
|
6. Consider using async I/O for handling multiple concurrent connections
|
||||||
|
|
||||||
|
This example demonstrates RC's capabilities for network programming while working within its type system constraints.
|
||||||
|
|
||||||
## Comments
|
## Comments
|
||||||
|
|
||||||
RC supports single-line comments using `//`.
|
RC supports single-line comments using `//`.
|
||||||
|
|||||||
@ -36,8 +36,8 @@ int main() {
|
|||||||
printf("Example: http://localhost:8080/\n\n");
|
printf("Example: http://localhost:8080/\n\n");
|
||||||
|
|
||||||
filename = "README.md";
|
filename = "README.md";
|
||||||
count = 0;
|
count = 1;
|
||||||
while (count < 100) {
|
while (count > 0) {
|
||||||
printf("Waiting for connection %d\n", count + 1);
|
printf("Waiting for connection %d\n", count + 1);
|
||||||
client_fd = accept(server_fd);
|
client_fd = accept(server_fd);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user