Web程式設計
Web程式設計.c
伺服器應答格式:
伺服器接收到瀏覽器的資料之後,需要判斷GET/後面跟的網頁是否存在,如果存在則請求成功,傳送指定的指令,併傳送檔案內容給瀏覽器,如果不存在,則傳送請求失敗的指令
請求成功:
"HTTP/1.1 200 OK\r\n " \
"Content-Type: text/html\r\n" \
"\r\n";
請求失敗
"HTTP/1.1 400 OK\r\n " \"
"Content-Type: text/html\r\n" \
"\r\n" \
"<HTML><BOOY>File not found</BODY></HTML>"
案例
/*
# Web程式設計
# https://www.cnblogs.com/kencszqh
#
# File Name: Web_servicer.c
# Created : 2024-06-13
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#define PATH "./xxxwork/"
#define N 128
#define ERR_LOG(errmsg) \
do \
{ \
perror(errmsg); \
exit(1); \
} while (0)
void *pthread_func(void *arg)
{
int acceptfd = *(int *)arg;
char buf[N] = {0};
char head[] = "HTTP/1.1 200 OK\r\n"
" Content-Type: text/html\r\n"
"\r\n ";
char err[] = "HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html\r\n"
"\r\n"
"<html><body><h1>404 Not Found</h1></body></html>";
// 接收瀏覽器透過HTTP協議傳送的資料包
if (recv(acceptfd, buf, N, 0) < 0)
{
ERR_LOG("recv");
}
printf("%s\n", buf);
// GET /index.html HTTP/1.1
char filename[N] = {0};
sscanf(buf, "GET /%s", filename); // sscanf()函式與空格結束,所以直接可以獲取到檔名
// 擷取檔名後判段一下是否是HTTP/1.1
if (strncmp(filename, "HTTP/1.1", strlen("http/1.1")) == 0)
{
strcpy(filename, "index.html");
}
printf("filename:%s\n", filename);
char path[N] = "PATH";
// 透過解析出來的網頁檔名,查詢本地中有沒有這個檔案
int fd;
if ((fd = open(path, O_RDONLY)) < 0)
{
// 如果檔案不存在,則發生不存在對應的指令
if (errno == ENOENT)
{
if (send(acceptfd, err, strlen(err), 0) < 0)
{
ERR_LOG("send");
}
close(acceptfd);
pthread_exit(NULL);
}
else
{
ERR_LOG("open");
}
}
// 如果檔案存在,則傳送檔案內容
if (send(acceptfd, head, strlen(head), 0) < 0)
{
ERR_LOG("send");
}
// 讀取檔案內容,併傳送給瀏覽器
ssize_t n;
char text[1024] = {0};
while ((n = read(fd, text, sizeof(text))) > 0)
{
if (send(acceptfd, text, n, 0) < 0)
{
ERR_LOG("send");
}
}
}
int main(int argc, char const *argv[])
{
if (argc != 3)
{
fprintf(stderr, "Usage:%s [ip] [port]\n", argv[0]);
exit(1);
}
int sockfd, acceptfd;
struct sockaddr_in serveraddr, clientaddr;
socklen_t addrlen = sizeof(serveraddr);
// 1.建立套接字
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
ERR_LOG("socket");
}
// 2.繫結
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
if (bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
{
ERR_LOG("bind");
}
// 3.監聽
if (listen(sockfd, 5) < 0)
{
ERR_LOG("listen");
}
// 4.接受客戶端連線
while (1)
{
if ((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) < 0)
{
ERR_LOG("accept");
}
printf("client ip:%s,port:%d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
pthread_t thread;
if (pthread_create(&thread, NULL, pthread_func, &acceptfd) != 0)
{
ERR_LOG("pthread_create");
}
pthread_detach(thread);
}
return 0;
}