github链接:c语言web服务器 这个服务器程序能够处理简单的GET请求,能够解析类似/%s或/./%s类的url 因为后期解析url时感觉c语言的原生字符串不太方便,所以自己简单封装了一个字符串库。 头文件:mystring.h
#ifndef MYSTRING_H
#define MYSTRING_H
typedef struct
{
char *data;
long length;
long ptr;
} String;
String initString();
void addChar(String *str, char ch);
void addString(String *dec, char *src, long len);
int isEqual(String src, char *dec);
long getStringSize(String str);
void freeString(String str);
char *toCString(String str);
#endif
对应的mystring.c
#include <stdlib.h>
#include <string.h>
#include "mystring.h"
#include "stringarray.h"
#define STRINGLENGTH 30
String initString()
{
String string;
string.length = STRINGLENGTH;
string.ptr = 0;
string.data = (char *)malloc(sizeof(char) * string.length);
return string;
}
void addChar(String *str, char ch)
{
if (str->ptr >= str->length)
{
str->length *= 2;
str->data = (char *)realloc(str->data, str->length);
}
str->data[str->ptr++] = ch;
}
void addString(String *dec, char *src, long len)
{
while (len--)
{
addChar(dec, *src);
src++;
}
}
int isEqual(String src, char *dec)
{
for (long i = 0; i < src.ptr; i++)
{
if (src.data[i] != dec[i])
{
return 0;
}
}
return 1;
}
long getStringSize(String str)
{
return str.ptr;
}
void freeString(String str)
{
free(str.data);
}
char *toCString(String str)
{
str.data[str.ptr] = 0;
return str.data;
}
然后封装了对mystring类型的列表操作 头文件stringarray.h
#ifndef STRINGARRAY_H
#define STRINGARRAY_H
#include "mystring.h"
typedef struct
{
String *data;
long length;
long ptr;
} StringArray;
StringArray initArray();
void pushBack(StringArray *array, String str);
long getArraySize(StringArray array);
String getString(StringArray array, long ptr);
StringArray split(String str, const char *pat);
void freeArray(StringArray array);
#endif
对应的stringarray.c
#include <stdlib.h>
#include <stdio.h>
#include "stringarray.h"
#define ARRAYLENGTH 30
StringArray initArray()
{
StringArray array;
array.length = ARRAYLENGTH;
array.data = (String *)malloc(sizeof(String) * array.length);
array.ptr = 0;
return array;
}
void pushBack(StringArray *array, String str)
{
if (array->ptr >= array->length)
{
array->length *= 2;
array->data = (String *)realloc(array->data, sizeof(String) * array->length);
}
array->data[array->ptr++] = str;
}
long getArraySize(StringArray array)
{
return array.ptr;
}
String getString(StringArray array, long ptr)
{
if (array.ptr <= ptr)
{
fprintf(stderr, "StringArray out of index\n");
exit(1);
}
return array.data[ptr];
}
StringArray split(String str, const char *pat)
{
StringArray array = initArray();
char *temp = str.data;
char *ptr;
long p = 0;
while ((ptr = strstr(temp, pat)) != NULL)
{
String x = initString();
while (temp != ptr)
{
addChar(&x, *temp);
temp++;
p++;
}
temp += strlen(pat);
p++;
pushBack(&array, x);
}
String x = initString();
while (p < str.ptr)
{
addChar(&x, *temp);
temp++;
p++;
}
pushBack(&array, x);
return array;
}
void freeArray(StringArray array)
{
free(array.data);
}
最后是main.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include "mystring.h"
#include "stringarray.h"
int server;
void interrupt(int x)
{
if (x == SIGINT)
{
shutdown(server, SHUT_RDWR);
close(server);
exit(0);
}
}
String numToStr(long x)
{
String ans = initString();
int ptr = 0;
int data[1000];
while (x)
{
data[ptr++] = x % 10;
x /= 10;
}
for(ptr--; ptr >= 0; ptr--)
{
addChar(&ans, (char) (data[ptr] + 0x30));
}
return ans;
}
void sender(int client, char *fileName)
{
String str = initString();
FILE *fp = fopen(fileName, "rb");
if (fp)
{
printf("200\n", fileName);
char *t = "HTTP/1.0 200 OK\r\n";
addString(&str, t, strlen(t));
addString(&str, "Content-Length: ", 16);
int x;
long len = 0;
String temp = initString();
while ((x = fgetc(fp)) != EOF)
{
len++;
addChar(&temp, (char) x);
}
String l = numToStr(len);
addString(&str, toCString(l), getStringSize(l));
addString(&str, "\r\n\r\n", 4);
addString(&str, toCString(temp), getStringSize(temp));
freeString(l);
freeString(temp);
fclose(fp);
}
else
{
printf("404\n", fileName);
addString(&str, "HTTP/1.1 404 Not Found\r\n\r\n", 26);
fp = fopen("404.html", "rb");
int x;
while ((x = fgetc(fp)) != EOF)
{
addChar(&str, (char) x);
}
fclose(fp);
}
write(client, toCString(str), str.ptr);
freeString(str);
}
void *handle(void *arg)
{
int client = *(int *)arg;
String str = initString();
char buffer[1024];
read(client, buffer, sizeof(buffer));
addString(&str, buffer, strlen(buffer));
StringArray array = split(str, "\r\n");
for (long i = 0; i < getArraySize(array); i++)
{
if (strstr(toCString(getString(array, i)), "GET"))
{
String url = getString(split(getString(array, i), " "), 1);
StringArray arr = split(url, "/");
printf("get %s ", toCString(url));
if (getArraySize(arr) == 2)
{
String fileName = getString(arr, 1);
sender(client, toCString(fileName));
freeString(fileName);
}
else if (getArraySize(arr) == 3 && isEqual(getString(arr, 1), "."))
{
String fileName = getString(arr, 2);
sender(client, toCString(fileName));
freeString(fileName);
}
freeString(url);
freeArray(arr);
}
}
freeArray(array);
freeString(str);
shutdown(client, SHUT_RDWR);
close(client);
return NULL;
}
int main()
{
char *addr = "127.0.0.1";
int port = 8080;
signal(SIGINT, interrupt);
server = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
serverAddr.sin_addr.s_addr = inet_addr(addr);
int x = bind(server, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
if (x != -1)
{
printf("Listen at %s:%d\n", addr, port);
listen(server, 1000);
struct sockaddr_in clientAddr;
socklen_t len = sizeof(clientAddr);
while (1)
{
int client = accept(server, (struct sockaddr *) &clientAddr, &len);
printf("connected by %s\n", inet_ntoa(clientAddr.sin_addr));
pthread_t th;
pthread_create(&th, NULL, handle, &client);
}
}
else
{
printf("%s:%d cannot be used\n", addr, port);
}
close(server);
return 0;
}
|