Ai
1 Star 1 Fork 0

kaxia-xia/http文件服务器

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
main.c 6.08 KB
一键复制 编辑 原始数据 按行查看 历史
forestrabbit 提交于 2023-07-30 20:59 +08:00 . 实现通过http获取文件的功能
#include <dirent.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <mstring.h>
#include <mime.h>
int run = 1;
//当按下ctrl-c时,执行此函数
void stop(int sig)
{
if (sig == SIGINT)
{
run = 0;
}
}
//将socket设置成非阻塞模式
void setSocketNIO(int sock)
{
int flag = fcntl(sock, F_GETFL, 0);
fcntl(sock, F_SETFL, flag | O_NONBLOCK);
}
//将sock注册到efd指定的epoll中
void registerSocket(int efd, int sock)
{
struct epoll_event ev;
ev.data.fd = sock;
ev.events = EPOLLIN || EPOLLET;
epoll_ctl(efd, EPOLL_CTL_ADD, sock, &ev);
}
//接受客户端连接并将连接注册到epoll
void acceptSock(int efd, int sock)
{
struct sockaddr_in cli;
int len = sizeof(cli);
int c = accept(sock, (struct sockaddr *)&cli, &len);
setSocketNIO(c);
registerSocket(efd, c);
}
//关闭并将socket从epoll中移除
void removeSock(int efd, int sock)
{
close(sock);
epoll_ctl(efd, EPOLL_CTL_DEL, sock, NULL);
}
//处理客户端连接
//根据url向客户端返回文件
void handle(int efd, int sock)
{
char ch;
int status = 0;
int isHeader = 1;
MString url = newString(), surl = newString();
char* curDir = getcwd(NULL, 0);
addRawString(&url, curDir);
free(curDir);
//处理request header
while (isHeader && (read(sock, &ch, sizeof(ch)) > 0 || errno == EAGAIN))
{
switch (status)
{
case 0:
if (ch == ' ')
{
status = 1;
}
else if (ch == '\n')
{
status = 3;
}
else if (ch == ':')
{
status = 5;
}
break;
case 1:
if (ch == ' ')
{
status = 2;
}
else if (ch == '\n')
{
status = 3;
}
else
{
addChar(&url, ch);
addChar(&surl, ch);
}
break;
case 2:
if (ch == '\n')
{
status = 3;
}
break;
case 3:
if (ch == '\r')
{
status = 4;
}
else
{
status = 0;
}
break;
case 4:
isHeader = 0;
break;
case 5:
if (ch == '\n')
{
status = 3;
}
else if (ch == ' ')
{
status = 6;
}
else
{
status = 7;
}
break;
case 6:
if (ch == '\n')
{
status = 3;
}
else
{
status = 7;
}
break;
case 7:
if (ch == '\n')
{
status = 3;
}
break;
}
}
struct stat buf;
stat(url.data, &buf);
if (access(url.data, 0) == 0 && S_ISREG(buf.st_mode))
{
FILE *fp = fopen(url.data, "rb");
fseek(fp, 0, SEEK_END);
long fileSize = ftell(fp);
rewind(fp);
MString ans = newString(), length = numToMStr(fileSize);
char *buffer = (char *)malloc(fileSize);
fread(buffer, fileSize, 1, fp);
fclose(fp);
addRawString(&ans, "HTTP/1.1 200 OK\r\nCache-Control: no-store\r\nContent-Type: ");
addRawString(&ans, getMimeType(url.data));
addRawString(&ans, "\r\nContent-Length: ");
addMString(&ans, length);
addRawString(&ans, "\r\n\r\n");
addRawString(&ans, buffer);
free(buffer);
write(sock, ans.data, ans.ptr);
freeString(ans);
freeString(length);
}
else if (access(url.data, 0) == 0 && S_ISDIR(buf.st_mode))
{
MString ans = newString(), data = newString();
addRawString(&ans, "HTTP/1.1 200 OK\r\nCache-Control: no-store\r\nContent-Type: text/html\r\nContent-Length: ");
addRawString(&data, "<!DOCTYPE html><html><head><meta charset=\"utf-8\" /></head><body><ul>");
struct dirent *filename;
DIR* dp = opendir(url.data);
while(filename = readdir(dp))
{
if (strcmp(filename->d_name, "..") != 0 && strcmp(filename->d_name, ".") != 0)
{
addRawString(&data, "<li><a href=\"");
addMString(&data, surl);
addRawString(&data, filename->d_name);
addRawString(&data, "\">");
addRawString(&data, filename->d_name);
addRawString(&data, "</a></li>");
}
}
addRawString(&data, "</ul></body></html>");
MString length = numToMStr(data.ptr);
addMString(&ans, length);
addRawString(&ans, "\r\n\r\n");
addMString(&ans, data);
write(sock, ans.data, ans.ptr);
freeString(ans);
freeString(data);
freeString(length);
}
else
{
char* ans = "HTTP/1.1 404 Not Found\r\nCache-Control: no-store\r\nContent-Type: text/html\r\nContent-Length: 23\r\n\r\n<h1>page not found</h1>";
write(sock, ans, strlen(ans));
}
freeString(url);
freeString(surl);
}
int main()
{
signal(SIGINT, stop); //按ctrl-C后停止程序
int epl = epoll_create(1);
//创建服务器socket
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
perror("创建服务器socket失败");
close(epl);
return -1;
}
setSocketNIO(sock);
//对socket进行监听绑定
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8080);
serverAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
int res = bind(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
if (res == -1)
{
perror("绑定服务器socket失败");
close(sock);
close(epl);
return -1;
}
listen(sock, 20);
registerSocket(epl, sock);
//处理客户端连接
while (run)
{
struct epoll_event events[50];
int n = epoll_wait(epl, events, 50, 0);
if (n < 0)
{
perror("epoll error");
close(sock);
close(epl);
return -1;
}
for (int i = 0; i <= n && run; i++)
{
int fd = events[i].data.fd;
if (fd == sock)
{
acceptSock(epl, fd);
}
else if (events[i].events & EPOLLHUP)
{
removeSock(epl, fd);
}
else if(events[i].events & EPOLLIN)
{
handle(epl, fd);
}
}
}
close(sock);
close(epl);
return 0;
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/kaxia-xia/http-file-server.git
git@gitee.com:kaxia-xia/http-file-server.git
kaxia-xia
http-file-server
http文件服务器
main

搜索帮助