#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int start_up(unsigned short *port){
int server_sock;
struct sockaddr_in name;
server_sock=socket(PF_INET, SOCK_STREAM, 0);
memset(&name,0,sizeof(name));
name.sin_family=AF_INET;
name.sin_port=htons(*port);
name.sin_addr.s_addr=htonl(INADDR_ANY);
socklen_t len=sizeof(name);
bind(server_sock,(struct sockaddr *)&name,sizeof(name));
if(*port==0){
getsockname(server_sock, (struct sockaddr *)&name, &len);
*port=ntohs(name.sin_port);
}
listen(server_sock,5);
return server_sock;
}
int get_line(int sock,char *str,int size){
int len=0;
char tmp;
while (len'\n')
{
int n=recv(sock,&tmp,1,0);
if (n>0)
{
if (tmp=='\r')
{
n=recv(sock,&tmp,1,MSG_PEEK);
if (n>0&&tmp=='\n')
{
recv(sock,&tmp,1,0);
}
else
tmp='\n';
}
str[len]=tmp;
len++;
}
else{
tmp='\n';
str[len]=tmp;
len++;
}
}
str[len]='\0';
return len;
}
void*accept_request(void *arg){
int cgi=0;
int client_socket=*(int*)arg;
char buf[1024];
int len=get_line(client_socket,buf,sizeof(buf));
char method[20];
int i=0;
for (i = 0;buf[i]!=' '&&imethod[i]=buf[i];
}
method[i]='\0';
if (strcasecmp(method,"GET")!=0&&strcasecmp(method,"POST")!=0)
{
//wrong;
}
while (buf[i]==' ')
i++;
char url[1024];
char query;
int j=0;
while (i' ')
{
url[j]=buf[i];
j++;i++;
}
url[j]='\0';
if (!strcasecmp(method,"GET"))
{
for (i = 0; i < strlen(url)&&url[i]!='?'; i++)
{
}
if (url[i]=='?'){
url[i]='\0';
query=1+url;
cgi=1;
}
}
if (!strcasecmp(method,"POST"))
cgi=1;
char path[1024];
sprintf(path,"htdocs%s",url);
if (path[strlen(path)-1]=='/')
strcat(path,"index.html");
struct stat st;
stat(path, &st);
if ((st.st_mode & S_IXUSR) ||
(st.st_mode & S_IXGRP) ||
(st.st_mode & S_IXOTH))
{
cgi=1;
}
if (cgi==1)
{
execute_cgi(client_socket);
}
else
serve_file(client_socket,path);
close(client_socket);
return NULL;
}
void header(int client,char *filename){
char buf[1024];
(void)filename; /* could use filename to determine file type *///有啥用???
/*正常的 HTTP header */
strcpy(buf, "HTTP/1.0 200 OK\r\n");
send(client, buf, sizeof(buf), 0);
/*服务器信息*/
strcpy(buf, "Server: jdbhttpd/0.1.0\r\n");
send(client, buf, sizeof(buf), 0);
sprintf(buf, "Content-Type: text/html\r\n");
send(client, buf, sizeof(buf), 0);
strcpy(buf, "\r\n");
send(client, buf, sizeof(buf), 0);
}
void cat(int client,FILE *resource){
char buf[1024];
fgets(buf, sizeof(buf), resource);
while (!feof(resource)) {
send(client, buf, strlen(buf), 0);
fgets(buf, sizeof(buf), resource);
}
}
void serve_file(int cli_sock,char *filepath){
FILE *re;
char buf[1024];
int numchar;
numchar=get_line(cli_sock,buf,sizeof(buf));
while (numchar>0&&strcmp(buf,"\n"))
{
numchar=get_line(cli_sock,buf,sizeof(buf));
}
re=fopen(filepath,"r");
header(cli_sock,filepath);
cat(cli_sock,re);
fclose(re);
}
void execute_cgi(int cli_sock,char *method,char *query,char *path){
int status;
char buf[1024];
int numchar;
int len_content;
if (strcasecmp(method,"GET")){
numchar=get_line(cli_sock,buf,sizeof(buf));
while (numchar>0&&strcmp(buf,'\n'))
numchar=get_line(cli_sock,buf,sizeof(buf));
}
else{
numchar=get_line(cli_sock,buf,sizeof(buf));
while (numchar>0&&strcmp(buf,'\n')){
buf[15]='\0';
if (!strcmp(buf,"Content-Length:")){
len_content=atoi(&buf[16]);
}
numchar=get_line(cli_sock,buf,sizeof(buf));
}
}
sprintf(buf, "HTTP/1.0 200 OK\r\n");
send(cli_sock, buf, strlen(buf), 0);
int input[2];
int output[2];
pipe(input);
pipe(output);
int pid=fork();
if (fork==0)
{
dup2(output[1],1);
dup2(input[0],0);
close(output[0]);
close(input[1]);
char meth_env[255];
char que_env[255];
char len_env[255];
sprintf(meth_env, "REQUEST_METHOD=%s", method);
putenv(meth_env);
if (strcasecmp(method,"GET"))
{
sprintf(que_env,"QUERY_STRING=%s",query);
putenv(que_env);
}
else{
sprintf(len_env,"CONTENT_LENGTH=%d",len_content);
putenv(len_env);
}
execl(path, path, NULL);
exit(0);
}
else{
close(output[1]);
close(input[0]);
char c;
for (int i = 0; i < len_content; i++)
{
recv(cli_sock,&c,1,0);
write(input[1],&c,1);
}
while (read(output[0],&c,1)>0)
{
send(cli_sock,&c,1,0);
}
close(output[0]);
close(input[1]);
waitpid(pid, &status, 0);
}
}
int main(){
int client_sock=-1;
int server_sock=-1;
unsigned short port=4000;
struct sockaddr_in client_name;
socklen_t client_name_len = sizeof(client_name);
pthread_t newthread;
server_sock=start_up(&port);
printf("httpd running on port %d\n", port);
while(1){
client_sock= accept(server_sock, (struct sockaddr *)&client_name,&client_name_len);
if(pthread_create(&newthread,NULL,accept_request,(void*)(intptr_t)&client_sock)!=0) {
perror("pthread_create");
}
}
close(server_sock);
return 0;
}
模仿写了一个tinyhttpd的c代码 调试过程中在accept_request函数 close(client_socket)关闭了客户端的套接字浏览器就显示The connection was reset ,如果用shutdown(client_socket,0) 代替close函数 ,访问服务器端口,浏览器就会一直处于加载界面 怎么解决呢
shutdown(client_socket,2);
close(client_socket);
不知道你这个问题是否已经解决, 如果还没有解决的话:一个轻量级的C语言HTTP服务端程序,500多行代码实现,具有清晰的结构,是一个良好的服务端入门程序。