c语言提供后端,提供页面显示跳转服务
后端代码:
#define SERVER_IP_ADDR "0.0.0.0" // 服务器IP地址
#define SERVER_PORT 8080 // 服务器端口号
#define BACKLOG 10
#define BUF_SIZE 8192
#define OK 1
#define ERROR 0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <time.h>
const char* Server_name = "Server: Web Server 1.0 - BooLo\r\n";
int Server_Socket_Init(int port);
int Handle_Request_Message(char* message, int Socket);
int Judge_URI(char* URI, int Socket);
int Send_Ifon(int Socket, const char* sendbuf, int Length);
int Error_Request_Method(int Socket);
int Inquire_File(char* URI);
int File_not_Inquire(int Socket);
int Send_File(char* URI, int Socket);
const char* Judge_Method(char* method, int Socket);
const char* Judge_File_Type(char* URI, const char* content_type);
const char* Get_Data(const char* cur_time);
const char* Post_Value(char* message);
int Logo();
// 创建套接字函数
int Server_Socket_Init(int port){
int ServerSock;
struct sockaddr_in ServerAddr;
// 创建套接字
ServerSock = socket(AF_INET, SOCK_STREAM, 0);
if(ServerSock < 0){
perror("Failed to create socket!");
exit(1);
}
// 配置服务器IP、端口信息
memset(&ServerAddr, 0, sizeof(ServerAddr));
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(port);
ServerAddr.sin_addr.s_addr = inet_addr(SERVER_IP_ADDR);
// 绑定
if(bind(ServerSock, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr)) < 0){
perror("Failed to bind stream socket!");
exit(1);
}
return ServerSock;
}
// 处理浏览器发送的数据
int Handle_Request_Message(char* message, int Socket){
int rval = 0;
char Method[BUF_SIZE];
char URI[BUF_SIZE];
char Version[BUF_SIZE];
if(sscanf(message, "%s %s %s", Method, URI, Version) != 3){
printf("Request line error!\n");
return ERROR;
}
printf("$$$ Method: %s, URI: %s, Version %s \n",Method, URI, Version);
if(Judge_Method(Method, Socket) == ERROR){
return ERROR;
}else if(strcmp(Judge_Method(Method, Socket), "POST") == 0){
Post_Value(message);
}
if(strcmp(URI, "/") == 0){
strcpy(URI, "/ndex.html");
}
if(Judge_URI(URI, Socket) == ERROR){
return ERROR;
} else {
rval = Send_File(URI, Socket); // 发送数据html文件或者其他
}
if(rval == OK){
printf("The process is successfully finished!\n");
}
return OK;
}
// 查看传入的请求类型 GET是向服务器获取数据,POST是向服务器提交数据
const char* Judge_Method(char* method, int Socket){
if(strcmp(method, "GET") == 0){
return "GET";
}else if(strcmp(method, "POST") == 0){
return "POST";
}else{
Error_Request_Method(Socket);
return ERROR;
}
}
int Judge_URI(char* URI, int Socket){
if (Inquire_File(URI) == ERROR){
File_not_Inquire(Socket);
return ERROR;
} else {
return OK;
}
}
// 等待数据被成功发送
int Send_Ifon(int Socket, const char* sendbuf, int Length){
int sendtotal = 0, bufleft, rval = 0;
bufleft = Length;
while(sendtotal < Length){
rval = send(Socket, sendbuf + sendtotal, bufleft, 0);
if(rval < 0){
break;
}
sendtotal += rval;
bufleft -= rval;
}
return rval < 0 ? ERROR : OK;
}
int Error_Request_Method(int Socket){
const char* Method_err_line = "HTTP/1.1 501 Not Implemented\r\n";
const char* cur_time = "";
const char* Method_err_type = "Content-type: text/plain\r\n";
const char* File_err_length = "Content-Length: 41\r\n";
const char* Method_err_end = "\r\n";
const char* Method_err_info = "The request method is not yet completed!\n";
printf("The request method from client's request message is not yet completed!\n");
if(Send_Ifon(Socket, Method_err_line, strlen(Method_err_line)) == ERROR){
printf("Sending method_error_line failed!\n");
return ERROR;
}
if(Send_Ifon(Socket, Server_name, strlen(Server_name)) == ERROR){
printf("Sending Server_name failed!\n");
return ERROR;
}
cur_time = Get_Data(cur_time);
Send_Ifon(Socket, "Date: ", 6);
if(Send_Ifon(Socket, cur_time, strlen(cur_time)) == ERROR){
printf("Sending cur_time error!\n");
return ERROR;
}
if(Send_Ifon(Socket, Method_err_type, strlen(Method_err_type)) == ERROR){
printf("Sending method_error_type failed!\n");
return ERROR;
}
if(Send_Ifon(Socket, Method_err_end, strlen(Method_err_end)) == ERROR){
printf("Sending method_error_end failed!\n");
return ERROR;
}
if(Send_Ifon(Socket, Method_err_info, strlen(Method_err_info)) == ERROR){
printf("Sending method_error_info failed!\n");
return ERROR;
}
return OK;
}
int Inquire_File(char* URI){
char cwd[BUF_SIZE];
if(getcwd(cwd, sizeof(cwd)) == NULL){
perror("getcwd() error");
return ERROR;
}
char abs_path[BUF_SIZE];
snprintf(abs_path, sizeof(abs_path), "%s%s", cwd, URI);
struct stat File_info;
if(stat(abs_path, &File_info) == -1){
return ERROR;
}else{
return OK;
}
}
int File_not_Inquire(int Socket) {
const char* File_err_line = "HTTP/1.1 404 Not Found\r\n";
const char* cur_time = "";
const char* File_err_type = "Content-type: text/html\r\n";
const char* File_err_end = "\r\n";
FILE* file;
struct stat file_stat;
char sendbuf[BUF_SIZE];
int send_length;
char cwd[BUF_SIZE];
if (getcwd(cwd, sizeof(cwd)) == NULL){
perror("getcwd() error");
return ERROR;
}
char abs_path[BUF_SIZE];
snprintf(abs_path, sizeof(abs_path), "%s/404.html", cwd);
file = fopen(abs_path, "rb");
if(file != NULL){
fstat(fileno(file), &file_stat);
if(Send_Ifon(Socket, File_err_line, strlen(File_err_line)) == ERROR){
printf("Sending file_error_line error!\n");
fclose(file);
return ERROR;
}
if(Send_Ifon(Socket, Server_name, strlen(Server_name)) == ERROR){
printf("Sending Server_name failed!\n");
fclose(file);
return ERROR;
}
cur_time = Get_Data(cur_time);
Send_Ifon(Socket, "Date: ", 6);
if(Send_Ifon(Socket, cur_time, strlen(cur_time)) == ERROR){
printf("Sending cur_time error!\n");
fclose(file);
return ERROR;
}
if(Send_Ifon(Socket, File_err_type, strlen(File_err_type)) == ERROR){
printf("Sending file_error_type error!\n");
fclose(file);
return ERROR;
}
char content_length[BUF_SIZE];
snprintf(content_length, sizeof(content_length), "Content-Length: %ld\r\n", file_stat.st_size);
if(Send_Ifon(Socket, content_length, strlen(content_length)) == ERROR){
printf("Sending file_error_length error!\n");
fclose(file);
return ERROR;
}
if(Send_Ifon(Socket, File_err_end, strlen(File_err_end)) == ERROR){
printf("Sending file_error_end error!\n");
fclose(file);
return ERROR;
}
while((send_length = fread(sendbuf, 1, BUF_SIZE, file)) > 0){
if (Send_Ifon(Socket, sendbuf, send_length) == ERROR) {
printf("Sending 404.html content error!\n");
break;
}
}
fclose(file);
}else{
printf("Failed to open 404.html!\n");
return ERROR;
}
return OK;
}
// 构建发送格式发送文件给浏览器函数
/**
* const char* response =
"HTTP/1.1 200 OK\r\n" // 状态行
"Date: Wed, 08 Jan 2025 12:00:00 GMT\r\n" // 日期时间
"Content-Type: text/html\r\n" // 内容类型
"Content-Length: 1234\r\n" // 内容长度
"\r\n" // 响应头结束
"<html>...</html>"; // 响应体(文件内容)
*/
int Send_File(char* URI, int Socket) {
char cwd[BUF_SIZE];
if(getcwd(cwd, sizeof(cwd)) == NULL){
perror("getcwd() error");
return ERROR;
}
char abs_path[BUF_SIZE];
snprintf(abs_path, sizeof(abs_path), "%s%s", cwd, URI); // 路径
const char* File_ok_line = "HTTP/1.1 200 OK\r\n"; // 成功响应
const char* cur_time = "";
const char* File_ok_type = "";
const char* File_ok_length = "Content-Length: ";
const char* File_ok_end = "\r\n";
FILE* file;
struct stat file_stat;
char Length[BUF_SIZE];
char sendbuf[BUF_SIZE];
int send_length;
if(Judge_File_Type(abs_path, File_ok_type) == ERROR){
printf("The request file's type from client's request message is error!\n");
return ERROR;
}
file = fopen(abs_path, "rb");
if(file != NULL){
fstat(fileno(file), &file_stat); // 获取文件储存信息
snprintf(Length, sizeof(Length), "%ld", file_stat.st_size);
if(Send_Ifon(Socket, File_ok_line, strlen(File_ok_line)) == ERROR){ // 发送接收信息成功头部
printf("Sending file_ok_line error!\n");
return ERROR;
}
if(Send_Ifon(Socket, Server_name, strlen(Server_name)) == ERROR){ // 发送服务器响应头
printf("Sending Server_name failed!\n");
return ERROR;
}
cur_time = Get_Data(cur_time);
Send_Ifon(Socket, "Date: ", 6);
if(Send_Ifon(Socket, cur_time, strlen(cur_time)) == ERROR){ // 发送时间日期信息
printf("Sending cur_time error!\n");
return ERROR;
}
File_ok_type = Judge_File_Type(abs_path, File_ok_type);
if(Send_Ifon(Socket, File_ok_type, strlen(File_ok_type)) == ERROR){ // 发送内容类型
printf("Sending file_ok_type error!\n");
return ERROR;
}
if(Send_Ifon(Socket, File_ok_length, strlen(File_ok_length)) != ERROR){ // 发送内容长度
if(Send_Ifon(Socket, Length, strlen(Length)) != ERROR){
if(Send_Ifon(Socket, "\n", 1) == ERROR){
printf("Sending file_ok_length error!\n");
return ERROR;
}
}
}
if(Send_Ifon(Socket, File_ok_end, strlen(File_ok_end)) == ERROR){ // 响应结束
printf("Sending file_ok_end error!\n");
return ERROR;
}
// 发送响应体
while(file_stat.st_size > 0){
if(file_stat.st_size < 1024){
send_length = fread(sendbuf, 1, file_stat.st_size, file);
if(Send_Ifon(Socket, sendbuf, send_length) == ERROR){
printf("Sending file information error!\n");
continue;
}
file_stat.st_size = 0;
}else{
send_length = fread(sendbuf, 1, 1024, file);
if(Send_Ifon(Socket, sendbuf, send_length) == ERROR){
printf("Sending file information error!\n");
continue;
}
file_stat.st_size -= 1024;
}
}
}else{
printf("The file is NULL!\n");
return ERROR;
}
return OK;
}
// 确定传输的文件类型
const char* Judge_File_Type(char* URI, const char* content_type) {
const char* suffix;
if ((suffix = strrchr(URI, '.')) != NULL)
suffix = suffix + 1;
if (strcmp(suffix, "html") == 0) {
return "Content-type: text/html\r\n";
} else if (strcmp(suffix, "jpg") == 0) {
return "Content-type: image/jpeg\r\n";
} else if (strcmp(suffix, "png") == 0) {
return "Content-type: image/png\r\n";
} else if (strcmp(suffix, "gif") == 0) {
return "Content-type: image/gif\r\n";
} else if (strcmp(suffix, "txt") == 0) {
return "Content-type: text/plain\r\n";
} else if (strcmp(suffix, "xml") == 0) {
return "Content-type: text/xml\r\n";
} else if (strcmp(suffix, "rtf") == 0) {
return "Content-type: text/rtf\r\n";
} else if (strcmp(suffix, "js") == 0) {
return "Content-type: application/javascript\r\n";
} else if (strcmp(suffix, "css") == 0) {
return "Content-type: text/css\r\n";
} else if (strstr(URI, ".mp3") != NULL) {
return "Content-Type: audio/mpeg\r\n";
} else {
return ERROR;
}
}
const char* Get_Data(const char* cur_time) {
time_t curtime;
time(&curtime);
cur_time = ctime(&curtime);
return cur_time;
}
const char* Post_Value(char* message) {
const char* suffix;
if ((suffix = strrchr(message, '\n')) != NULL)
suffix = suffix + 1;
printf("\n\n$$$$-1 Post Value: %s\n\n", suffix);
return suffix;
}
int Logo() {
printf("/ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄\n");
printf("| 程序启动了!\n");
printf(" \n");
printf("  ̄ ̄∨ ̄ ̄ ̄ ̄ ̄ ̄\n");
printf(" ∧_∧\n");
printf(" ( ∧_∧) \n");
printf(" ( つつヾ\n");
printf(" | | |\n");
printf(" (__)_)\n");
printf("\n");
printf("___________________________________________________________\n\n");
return OK;
}
int main(int argc, char* argv[]) {
// 初始化套接字
int port = SERVER_PORT;
if (argc == 2) {
port = atoi(argv[1]);
}
int ServerSock, MessageSock;
struct sockaddr_in ClientAddr;
int rval, Length;
char revbuf[BUF_SIZE];
Logo();
printf("Web Server is starting on port %d...\n\n", port);
ServerSock = Server_Socket_Init(port);
printf("\n-----------------------------------------------------------\n");
// 监听和处理请求
rval = listen(ServerSock, BACKLOG); // 监听
if (rval < 0) {
perror("Failed to listen socket!");
exit(1);
}
printf("Listening the socket on port %d...\n", port);
Length = sizeof(ClientAddr);
while (OK) {
MessageSock = accept(ServerSock, (struct sockaddr*)&ClientAddr, &Length); // 创建与客户端通信的套接字
if (MessageSock < 0) {
perror("Failed to accept connection from client!");
exit(1);
}
printf("Succeed to accept connection from [%s:%d] !\n\n", inet_ntoa(ClientAddr.sin_addr), ntohs(ClientAddr.sin_port));
memset(revbuf, 0, BUF_SIZE);
rval = recv(MessageSock, revbuf, BUF_SIZE, 0);
if (rval <= 0) {
printf("Failed to receive request message from client!\n");
} else {
printf("$$$$$$ recvbuf: %s\n", revbuf);
rval = Handle_Request_Message(revbuf, MessageSock);
}
printf("\n-----------------------------------------------------------\n");
close(MessageSock);
}
close(ServerSock);
return OK;
}
效果:
浏览器通过访问http://localhost:8080/与后端建立连接
后端主要为浏览器提供服务操作,而前端主要接收后端传递的数据,做渲染显示
前端的每次请求,后端都会创建一个与前端通信的套接字,用以回复消息
前端发送给后端的消息,后端发送给前端的消息都是有格式的,所以后端接收消息要做拆解解读,后端发送消息的时候要做封装
后端根据前端需求会发送很多类型的数据,如html数据用于给前端做跳转做渲染,音乐二进制文件或者图片文件用于给前端做声音响应或显示