c语言 服务器程序,简单web服务器实现(C语言)

刚接触linux,参考了《深入理解计算机系统》中网络编程的内容,再ubuntu下用C实现了一个简单的web服务器----代码写得比较乱,还不是很熟悉socket编程,可能会有bug。

——

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define MAXLINE 8192

#define MAXLEN 8192

#define IP "127.0.0.1"

#define PORT 8080

#define WebRoot "/home/wjh/myweb"

typedef struct sockaddr SA;

typedef struct sockaddr_in SA_IN;

const int clientNumber=1024;

typedef struct

{

int rio_fd;

int rio_cnt;

char *rio_bufptr;

char rio_buf[MAXLEN];

} rio_t;

//Rio函数

ssize_t rio_readn(int fd,void *buf,size_t n);

ssize_t rio_writen(int fd,void *buf,size_t n);

void rio_readinitb(rio_t *rp,int fd);

ssize_t rio_readlineb(rio_t *rp,void *buf,size_t n);

ssize_t rio_readnb(rio_t *rp,void *buf,size_t n);

//返回错误信息

void showerror(int fd,char *cause,char*errnum,char *shortmsg,char *longmsg);

int main(int argc,char **argv)

{

int listenfd,fd,len;

SA_IN serveraddr,clientaddr;

//建立服务器端socket

if((listenfd=socket(AF_INET,SOCK_STREAM,0))<0){

printf("Fail to create a server socket.\n");

exit(1);

}

//设置IP与PORT

bzero(&serveraddr,sizeof(serveraddr));

serveraddr.sin_family=AF_INET;

serveraddr.sin_addr.s_addr=inet_addr(IP);

serveraddr.sin_port=htons(PORT);

//绑定

if(bind(listenfd,(SA*)&serveraddr,sizeof(serveraddr))<0){

printf("Fail to bind.\n");

exit(1);

}

//监听

if(listen(listenfd,clientNumber)<0){

printf("Fail to listen.\n");

exit(1);

}

//服务器启动完毕

printf("The WJH Web Server is listening on %d.\n",PORT);

len=sizeof(clientaddr);

while(1)

{

//客户端请求连接

fd=accept(listenfd,(SA*)&clientaddr,&len);

//printf("%d\n",fd);

struct stat sbuf; //储存文件属性的结构

char buf[MAXLINE],method[MAXLINE],uri[MAXLINE],version[MAXLINE];

char filename[MAXLINE];

rio_t rio;

//读取请求行

rio_readinitb(&rio,fd);

rio_readlineb(&rio,buf,MAXLINE);

//printf("%s\n",buf);

sscanf(buf,"%s %s %s",method,uri,version);

//输出请求关键信息

printf("%s %s %s\n",method,uri,version);

if(strcasecmp(method,"GET")){

showerror(fd,method,"501","Not Implemented","WJH does not implement this method");

close(fd);

exit(1);

}

rio_readlineb(&rio,buf,MAXLINE);

//打印协议内容

while(strcmp(buf,"\r\n")){

rio_readlineb(&rio,buf,MAXLINE);

printf("%s",buf);

}

//默认路径为WebRoot

strcpy(filename,WebRoot);

strcat(filename,uri);

//如果用户请求中不包含文件名,默认为index.html

if(strcmp(uri,"/")==0){

strcat(filename,"index.html");

}

//printf("%s\n",filename);

if(stat(filename,&sbuf)<0){ //文件是否存在?

showerror(fd,filename,"404","Not found","WJH couldn't find this file");

close(fd);

exit(1);

}

if(!(S_ISREG(sbuf.st_mode))||!(S_IRUSR&sbuf.st_mode)){ //普通可读文件?

showerror(fd,filename,"403","Forbidden","WJH couldn't read the file");

close(fd);

exit(1);

}

int srcfd;

char *srcp,filetype[MAXLINE];

int filesize=sbuf.st_size;

//服务器暂时只实现两text/html类型文件的请求响应

strcpy(filetype,"text/html");

sprintf(buf,"HTTP/1.0 200 OK\r\n");

sprintf(buf,"%sServer: WJH Web Server\r\n",buf);

sprintf(buf,"%sContent-length: %d\r\n",buf,filesize);

sprintf(buf,"%sContent-type: %s\r\n\r\n",buf,filetype);

rio_writen(fd,buf,strlen(buf));

srcfd=open(filename,O_RDONLY,0);

srcp=mmap(0,filesize,PROT_READ,MAP_PRIVATE,srcfd,0);//将文件映射到一片内存上

close(srcfd);

rio_writen(fd,srcp,filesize);//将内存上的文件内容返回客户端

munmap(srcp,filesize);//解除文件与内存的映射关系

close(fd);

}

return 0;

}

ssize_t rio_readn(int fd,void *buf,size_t n)

{

ssize_t nread;

size_t nleft=n;

char *bp=(char *)buf;

while(nleft>0)

{

if((nread=read(fd,bp,nleft))<0)

{

if(errno==EINTR)

nread=0;

else

return -1;

}

else if(nread==0)

break;

nleft-=nread;

bp+=nread;

}

return (n-nleft);

}

ssize_t rio_writen(int fd,void *buf,size_t n)

{

ssize_t nwritten;

size_t nleft=n;

char *bp=(char *)buf;

while(nleft>0)

{

if((nwritten=write(fd,bp,nleft))<=0)

{

if(errno==EINTR)

nwritten=0;

else

return -1;

}

nleft-=nwritten;

bp+=nwritten;

}

return n;

}

void rio_readinitb(rio_t *rp,int fd)

{

rp->rio_fd=fd;

rp->rio_cnt=0;

rp->rio_bufptr=rp->rio_buf;

}

static ssize_t rio_read(rio_t *rp,void *buf,size_t n)

{

ssize_t cnt;

while(rp->rio_cnt<=0)

{

rp->rio_cnt=read(rp->rio_fd,rp->rio_buf,sizeof(rp->rio_buf));

if(rp->rio_cnt<0)

{

if(errno!=EINTR)

return -1;

}

else if(rp->rio_cnt==0)

return 0;

else

rp->rio_bufptr=rp->rio_buf;

}

cnt=n;

if(rp->rio_cnt

cnt=rp->rio_cnt;

memcpy(buf,rp->rio_bufptr,cnt);

rp->rio_cnt-=cnt;

rp->rio_bufptr+=cnt;

return cnt;

}

ssize_t rio_readlineb(rio_t *rp,void *buf,size_t n)

{

size_t i,ret;

char c;

char *bp=(char *)buf;

for(i=1;i

{

if((ret=rio_read(rp,&c,1))==1)

{

*bp++=c;

if(c=='\n')

break;

}

else if(ret==0)

{

if(i==1)

return 0;

else

break;

}

else

return -1;

}

*bp='\0';

return i;

}

ssize_t rio_readnb(rio_t *rp,void *buf,size_t n)

{

ssize_t nread;

size_t nleft=n;

char *bp=(char *)buf;

while(nleft>0)

{

if((nread=rio_read(rp,bp,nleft))<0)

{

if(errno==EINTR)

nread=0;

else

return -1;

}

else if(nread==0)

break;

nleft-=nread;

bp+=nread;

}

return (n-nleft);

}

void showerror(int fd,char *cause,char *errnum,char *shortmsg,char *longmsg)

{

char buf[MAXLINE],body[MAXLINE];

sprintf(body,"WJH Error");

sprintf(body,"%s

\r\n",body);

sprintf(body,"%s%s: %s\r\n", body,errnum,shortmsg);

sprintf(body,"%s

%s: %s\r\n",body,longmsg,cause);

sprintf(body,"%s


The WJH Web server\r\n",body);

sprintf(buf,"HTTP/1.0 %s %s\r\n",errnum,shortmsg);

rio_writen(fd,buf,strlen(buf));

sprintf(buf,"Content-type: text/html\r\n");

rio_writen(fd,buf,strlen(buf));

sprintf(buf,"Content-length: %d\r\n\r\n",(int)strlen(body));

rio_writen(fd,buf,strlen(buf));

rio_writen(fd,body,strlen(body));

}

编译并运行:

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

浏览器发出请求:

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值