一个以前练手的demo:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#define SERVER_PORT 80
#define debug 1
int get_line(int sock,char *buf,int size);
void do_http_request(int client_sock);
void do_http_response(int client_sock,int fd);
void not_found(int client_sock);
int main(void){
int sock,ret,opt=1;
struct sockaddr_in server_addr;
sock = socket(AF_INET,SOCK_STREAM,0);
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port=htons(SERVER_PORT);
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
ret =bind(sock,(struct sockaddr*)&server_addr,sizeof(server_addr));
if(ret==-1){
perror("bind is error.\n");
}
ret =listen(sock,5);
if(ret==-1){
perror("listen is error.\n");
}
printf("等待客户端连接!\n");
while (1)
{
struct sockaddr_in client;
int client_sock,len;
char buff[256],client_ip[32];
char send_buff[256];
/*socklen_t client_addr_len = sizeof(client);*/
socklen_t client_addr_len = sizeof(client);
client_sock=accept(sock,(struct sockaddr*)&client,&client_addr_len);
printf("client ip:%s\tport:%d\n",inet_ntop(AF_INET,&client.sin_addr,client_ip,sizeof(client_ip)),ntohs(client.sin_port));
//读取http请求
do_http_request(client_sock);
/*close(client_sock);*/
}
close(sock);
return 0;
}
void do_http_response(int client_sock,int fd){
char send_buff[1024*1024];
int size = lseek(fd,0,SEEK_END);//获取文件内容大小
lseek(fd,0,SEEK_SET);//将文件指针设置到起始位置
const char * main_header="HTTP/1.0 200 OK\r\nServer:Wuxin Server\r\nContent-Type:test-html\r\nConnection:Close";
//1.发送main_header
int len = write(client_sock,main_header,strlen(main_header));
if(debug)fprintf(stdout,"do http_response.\n");
if(debug)fprintf(stdout,"write[%d]:%s\n",len,main_header);
//2.生成Content-Length
len = snprintf(send_buff,64,"Content-Length:%d.\r\n\r\n",size);
len = write(client_sock,send_buff,len);
if(debug)fprintf(stdout,"write[%d]:%s\n",len,send_buff);
//3.将文件内容发送出去
len = read(fd,send_buff,size);
if(len>0){
write(client_sock,send_buff,strlen(send_buff));
}else if(len==0){
fprintf(stdout,"close connect!\n");
}
else {
fprintf(stderr,"read failed.reason:%s",strerror(errno));
}
close(fd); // 关闭资源文件描述符
close(client_sock); // 关闭连接套接字
/*if(debug)fprintf(stdout,"write[%d]:%s\n",len,send_buff);*///打印出发送的数据
}
void do_http_request(int client_sock){
char buff[256],method[64],url[256],path[256];
int len=0;
//读取客服端发送的请求
len = get_line(client_sock,buff,sizeof(buff));
/*printf("read line:%s\n",buff);*/
if(len>0){
int i=0,j=0;
while (!isspace(buff[j])&&i<sizeof(method)-1)
{
method[i]=buff[j];
i++;
j++;
}
method[i]='\0';
if(debug)printf("request mthod:%s\n",method);
if(strncasecmp(method,"GET",3)==0){
//不区分大小写的字符串比较
if(debug)printf("request = GET\n");
while(isspace(buff[j++]));//跳过空格
i=0;
while (!isspace(buff[j])&&i<sizeof(url)-1)
{
url[i]=buff[j];
i++;
j++;
}
url[i]='\0';
if(debug)printf("request url:%s\n",url);
do{
//读完request
len = get_line(client_sock,buff,sizeof(buff));
if(debug)printf("read:%s\n",buff);
}while(len>0);
//定位服务器中html文件
char * pos = strchr(url,'?');
if(pos) {
*pos='\0';
printf("rear url:%s\n",url);
}
sprintf(path,"./html_docs/%s",url);
if(debug)printf("path:%s\n",path);
int fd=open(path,O_RDONLY);
if(fd==-1){
//文件不存在 出错
fprintf(stderr,"stat %s failed.reason:%s.\n",path,strerror(errno));
not_found(client_sock);
close(fd);
}else{
do_http_response(client_sock,fd);
}
} else{
//不是GET请求
fprintf(stderr,"other request %s\n",method);
do{
//读完request 未实现响应
len = get_line(client_sock,buff,sizeof(buff));
if(debug)printf("read:%s\n",buff);
}while(len>0);
}
}
}
void not_found(int client_sock){
const char * reply ="HTTP/1.0 404 NOT FOUND\r\n\
Content-Type: text/html\r\n\
\r\n\
<HTML lang=\"zh-CN\">\r\n\
<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\">\r\n\
<HEAD>\r\n\
<TITLE>NOT FOUND</TITLE>\r\n\
</HEAD>\r\n\
<BODY>\r\n\
<P>文件不存在!\r\n\
<P>The server could not fulfill your request because the resource specified is unavailable or nonexistent.\r\n\
</BODY>\r\n\
</HTML>\n";
int len = write(client_sock,reply,strlen(reply));
if(debug) fprintf(stdout,reply);
if(len<0){
fprintf(stderr,"send reply error.reason:%s.\n",strerror(errno));
}
}
int get_line(int sock,char *buf,int size){
int count=0,len=0;
char ch='\0';
while (count<size-1&&ch!='\n')
{
len=read(sock,&ch,1);
if(len==1){
//读取正常
if(ch=='\r'){
//回车符
continue;
}else if(ch=='\n'){
//换行符
// buf[count]='0';
break;
}
//正常读一个字符
buf[count]=ch;
count++;
}else if(len==-1){
//读出错
perror("get line error!\n");
count=-1;
break;
} else{
//读取到0个字符 客户端关闭
fprintf(stderr,"client close!\n");
count=-1;
break;
}
}
if(count>=0)buf[count]='\0';
return count;
}
运行截图如下:
网站页面为直接复制的html.
包含解析http头部.返回资源请求等功能.