标准c语言实现web,C语言实现简单的Web服务端

这个博客内容展示了如何实现一个简单的HTTP服务器,它能够解析URL,根据文件后缀返回相应的Content-Type,并处理错误情况。源代码中定义了一个结构体来存储文件后缀与MIME类型的映射,并提供了通过文件后缀获取Content-Type的函数。服务器能够接收请求,发送响应头和文件内容。当文件不存在或无法打开时,服务器会返回错误页面。
摘要由CSDN通过智能技术生成

#include

#include

#include

#pragma comment(lib,"ws2_32.lib")

#define HTTP_PORT 80

#define HTTP_BUF_SIZE 1024

#define NAME_SIZE 1024

#define PATH_SIZE 1024

struct doc_type

{

char *suffix;//文件后缀

char *type; //文件类型

};

struct doc_type file_type[]=

{

{"html","text/html"},

{"htm","text/html"},

{"txt","text/plain"},

{"jpg","image/jpeg"},

{"gif","image/gif"},

{"bmp","application/x-bmp"},

{"ico","application/x-ico"},

{"swf","application/x-shockwave-flash"},

{NULL,NULL},

};

//响应的首部内容

char *http_head_temp="HTTP/1.1 200 OK\r\nServer:Wayne's Server \r\n"

"Accept-Ranges:bytes\r\nContent-Length:%d\r\nConnection:close\r\n"

"Content-Type:%s\r\n\r\n";

//通过文件后缀查找对应的文件类型Content-Type

char *http_get_type_by_suffix(char *suffix)

{

struct doc_type *ty;

for(ty=file_type; (*ty).suffix; ty++)

if(strcmp((*ty).suffix,suffix)==0)

return (*ty).type;

return NULL;

}

//通过URL获取访问文件名和后缀

int http_analyse_url(char *buf,int buflen,char *file_path,char *file_name,char *suffix)

{

int length=0,i=0,j,k=0;

char *begin,*end,*bias,*p,*start;

for(j=0;j

if(buf[j]==' ') k++;

if(k<2) return -1;

begin=strchr(buf,' ');

begin++;

for(p=begin; *p=='/'; p++) begin=p;

start=begin; //start开始的位置不包括“/”

end=strchr(begin,' ');

for(p=begin; p!=end; p++)

if(*p=='/') begin=p;

begin++; //将指针定位到最后一个‘/’的后面一位

for(p=begin; p!=end; p++)

if(*p=='.') i=1; //判断最后后缀是否有“.”,有表示访问的是文件,无表示访问的是路径

if(i==0)

{

length=end-start; //获取访问路径长度

memcpy(file_path,start,length);

}

else

{

length=begin-start;

memcpy(file_path,start,length);

}

for(p=file_path; *p!=NULL; p++)

if(*p=='/') *p='\\'; //将路径中的'/'改为'\'

p--;

if(*p!='\\')

{

//在路径的最后添加'\'

p++;

*p='\\';

}

if(i==1)

{

length=end-begin; //获取文件名长度

memset(file_name,NULL,NAME_SIZE);

memcpy(file_name,begin,length);

for(p=begin; p!=end; p++)

if(*p=='.') begin=p; //定位到最后一个'.'

begin++;

length=end-begin; //获取扩展名长度

memset(suffix,NULL,NAME_SIZE);

memcpy(suffix,begin,length);

return 1; //定义了访问目标

}

return 0; //没有定义访问目标

}

void error(SOCKET soc)

{

int file_len=46,hdr_len;

char http_header[HTTP_BUF_SIZE],*Content_type="text/html";

char error[HTTP_BUF_SIZE]="

ERROR

"; //46

memset(http_header,NULL,HTTP_BUF_SIZE);

hdr_len=sprintf(http_header,http_head_temp,file_len,Content_type); //格式化首部内容

send(soc,http_header,hdr_len,0);

send(soc,error,file_len,0);

printf("访问出错\n========================================================================\n");

}

int http_send_response(SOCKET soc,char *buf,int buf_len)

{

FILE *file=NULL;

char http_header[HTTP_BUF_SIZE],file_name[NAME_SIZE]="index.html",file_name2[NAME_SIZE]="index.htm",file_path[PATH_SIZE],file_path_temp[PATH_SIZE],suffix[NAME_SIZE]="html";

char HTTP_Send_Buff[HTTP_BUF_SIZE],*Content_type=NULL,read_buf[HTTP_BUF_SIZE],*p,*q,target_file[NAME_SIZE];

int file_len=0,hdr_len=0,send_len=0,read_len=0;

int results,i=0;

memset(file_path,NULL,PATH_SIZE);

if((results=http_analyse_url(buf,HTTP_BUF_SIZE,file_path,file_name,suffix))==-1)

{

error(soc);

return -1;

}

memset(target_file,NULL,NAME_SIZE);

for(p=file_path; *p!=NULL; p++)

{

if(*p=='\\')

{

p++;

memset(file_path_temp,NULL,PATH_SIZE);

for(q=p; *q=='\\'; q++);

memcpy(file_path_temp,q,strlen(q));

memcpy(p,file_path_temp,strlen(file_path_temp));

if(strlen(file_path_temp)==0)

{

*p=NULL;

break;

}

}

}

strcat(target_file,&file_path[1]);

strcat(target_file,file_name);

if(results==1)

{

if((file=fopen(target_file,"rb"))==NULL)

{

printf("访问\"%s\"失败,不存在此文件\n",target_file);

error(soc);

return -1;

}

}

//获取文件大小

else

{

if((file=fopen(target_file,"rb"))==NULL)

{

memset(target_file,NULL,NAME_SIZE);

strcat(target_file,&file_path[1]);

strcat(target_file,file_name2);

if((file=fopen(target_file,"rb"))==NULL)

{

printf("无首页文件\n");

error(soc);

return -1;

}

}

}

printf("访问文件:%s\n",target_file);

fseek(file,0,SEEK_END);

file_len=ftell(file);

fseek(file,0,SEEK_SET);

if((Content_type=http_get_type_by_suffix(suffix))==NULL)

{

puts("无此文件类型");

error(soc);

return -1;

}

hdr_len=sprintf(http_header,http_head_temp,file_len,Content_type); //格式化首部内容

if((send_len=send(soc,http_header,hdr_len,0))==SOCKET_ERROR)

{

return -1;

}

do

{

read_len=fread(read_buf,sizeof(char),HTTP_BUF_SIZE,file);

if(read_len>0)

{

send_len=send(soc,read_buf,read_len,0);

file_len-=read_len;

}

}

while((read_len>0)&&(file_len>0));

fclose(file);

printf("========================================================================\n");

return 1;

}

int main(int argc,char argv[]) { WSADATA wsa; SOCKET srv_soc,acpt_soc; struct sockaddr_in serv_addr; struct sockaddr_in from_addr; char recv_buf[HTTP_BUF_SIZE]; memset(recv_buf,NULL,sizeof(recv_buf)); int port=HTTP_PORT,from_len=sizeof(from_addr),recv_len; /*if(argc==2) { port=atoi(argv[1]); }*/ WSAStartup(MAKEWORD(2,0),&wsa); if((srv_soc=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET) exit(0); serv_addr.sin_family=AF_INET; serv_addr.sin_port=htons(port); serv_addr.sin_addr.s_addr=htonl(INADDR_ANY); if(bind(srv_soc,(struct sockaddr *)&serv_addr,sizeof(serv_addr))==SOCKET_ERROR) { puts("绑定地址失败"); system("pause"); exit(0); } if(listen(srv_soc,SOMAXCONN)!=0) { puts("套接口转被动模式失败"); system("pause"); exit(0); } printf("The Service Started...\n"); while(1) { if((acpt_soc=accept(srv_soc,(struct sockaddr *)&from_addr,&from_len))==INVALID_SOCKET) { puts("接受客户端连接服务启动失败"); closesocket(acpt_soc); continue; } printf("客户端%s接入\n",inet_ntoa(from_addr.sin_addr)); if(recv(acpt_soc,recv_buf,HTTP_BUF_SIZE,0)==SOCKET_ERROR) { puts("接收数据失败"); closesocket(acpt_soc); continue; } recv_buf[HTTP_BUF_SIZE-1]=NULL; http_send_response(acpt_soc,recv_buf,recv_len); closesocket(acpt_soc); } }

### 回答1: 在C语言中搭建一个多进程并发的Web服务器是实现Web应用的一种常见方式。这种方式的主要优点是能够处理多个客户端的请求,并且能够实现并发处理,提高了服务器的性能。 实现一个多进程的Web服务器基本步骤如下: 1. 创建一个父进程,用于监听指定的网络端口,并接受客户端的连接请求。 2. 父进程接收到客户端的连接请求后,创建一个子进程来处理该请求。 3. 子进程负责接收和解析客户端的HTTP请求,并根据请求的内容生成相应的HTTP响应。 4. 子进程将生成的HTTP响应发送给客户端,完成请求处理后,子进程可以自行退出。 5. 父进程继续监听指定网络端口,接受下一个客户端的连接请求。 通过多进程的方式,可以实现同时处理多个客户端请求的能力并提高并发处理能力。父进程只负责接受连接请求并创建子进程,而子进程则负责具体的请求处理。不同的子进程之间相互独立,互不影响,可以同时处理多个请求。 需要注意的是,多进程的方式可能会导致一些资源的浪费,比如每个子进程都需要单独的内存空间和资源。另外,也要注意处理子进程的退出和异常情况,以及进程间的通信和同步问题。 总之,通过使用C语言搭建多进程并发的Web服务器,可以实现高性能的Web应用服务端,有效地处理多个客户端的请求,提供更好的用户体验。 ### 回答2: C语言通过使用多进程来实现Web服务器的并发是一种常见的方法。这种方法基于操作系统提供的进程控制功能,可以同时处理多个客户端的请求。下面是一个使用C语言构建具有多进程并发功能的Web服务器的示例: 首先,我们需要使用C语言中的系统调用函数(如fork()和exec())来创建子进程。父进程负责监听客户端请求,而子进程负责处理请求并向客户端发送响应。 在主程序中,我们需要创建一个主进程,用于监听客户端的连接请求。主进程使用socket函数创建一个TCP连接,然后使用bind和listen函数将其绑定到一个特定的端口上,并开始监听客户端的连接请求。 一旦有客户端连接请求到达,主进程使用accept函数来接受该连接请求,并创建一个子进程来处理它。子进程通过调用fork函数来复制主进程的地址空间,并可以继续执行与主进程相同的代码。 在子进程中,我们需要使用exec函数来执行一个新的程序,比如一个CGI脚本或者是处理静态文件的函数。在这个过程中,子进程与客户端进行通信,接收并处理请求并再次发送响应。 当子进程完成处理后,它会关闭与客户端的连接,并通过exit函数退出。父进程会继续监听其他客户端的连接请求,并创建新的子进程来处理它们。 通过这种方式,我们可以实现一个基于C语言的多进程并发的Web服务器。这种方法可以提供快速的响应速度,允许服务器同时处理多个客户端请求。但是,它也会消耗更多的系统资源,并且在高并发情况下可能会导致系统负载过重。因此,在实际应用中,我们需要根据具体情况选择最合适的并发模型来构建Web服务器。 ### 回答3: C语言搭建Web服务器实现多进程并发主要有以下几个步骤: 1. 创建Socket:首先,我们需要使用Socket函数创建一个服务器端的套接字,指定服务器端监听的IP地址和端口号。 2. 绑定Socket:使用bind函数将服务器端套接字与指定的IP地址和端口号进行绑定。 3. 监听连接请求:使用listen函数开始监听来自客户端的连接请求。 4. 接受连接请求:使用accept函数等待并接受客户端的连接请求,当有客户端请求连接时,accept函数将返回一个新的套接字。 5. 创建子进程:当接受到客户端的连接请求后,使用fork函数创建一个子进程,子进程将负责与该客户端进行通信。 6. 子进程处理请求:在子进程中,使用recv函数接收来自客户端的HTTP请求,并根据请求的内容生成相应的HTTP响应。 7. 发送响应:使用send函数将生成的HTTP响应发送给客户端。 8. 关闭连接:在通信结束后,关闭子进程中的套接字,并终止子进程的执行。 9. 父进程继续监听:父进程在子进程处理完请求并关闭套接字后,继续监听其他客户端的连接请求,重复上述步骤。 通过以上步骤,我们就可以使用C语言搭建一个能够实现多进程并发的Web服务器。每个接收到的客户端请求都会创建一个独立的子进程进行处理,从而实现了并发处理多个客户端请求的能力。这种方式可以提高服务器的并发性能,同时确保每个客户端请求都能够得到及时的响应。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值