基于c++编写的简单web服务器程序
使用vs2012 编程软件
程序执行流程;
1、创建一个ServerSocket对象;
2、调用ServerSocket对象的accept方法,等待连接,连接成功会返回一个Socket对象,否则一直阻塞等待;
3、从Socket对象中获取InputStream和OutputStream字节流,这两个流分别对应request请求和response响应;
4、处理请求:读取InputStream字节流信息,转成字符串形式,并解析,这里的解析比较简单,仅仅获取uri(统一资源标识符)信息;
5、处理响应:根据解析出来的uri信息,从WEB_ROOT目录中寻找请求的资源资源文件, 读取资源文件,并将其写入到OutputStream字节流中;
6、关闭Socket对象;
7、转到步骤2,继续等待连接请求;
将要请求的html文件放置到工程目录下
打开IE 指定地址端口号 请求文件index.html
浏览器显示:
服务器端:
附源代码:
#include
#include
#include
#include
#include
#include
#include
#pragma comment(lib, "Ws2_32.lib")
bool InitSocket();
int endsWith(char s1[],char s2[]);
using namespace std;
int main(int argc, char *argv[])
{
struct sockaddr ser_addr,client_addr;
int off;
bool over;
char msg[1003];
char msgtp[450];
SOCKET welcomesock ;
if( !InitSocket() ) return 0; //初始化Window Sockets DLL(ws2_32.dll)
welcomesock = socket( AF_INET,SOCK_STREAM,0 ); //创建流Socket:即传输层使用TCP
if( welcomesock==INVALID_SOCKET ){ //不能创建,返回
printf("不能创建Socket!");
getch();
WSACleanup( ); //卸载Window Sockets DLL
return 0;
}
//设置服务器IP地址和端口号
((sockaddr_in*)&ser_addr)->sin_family = AF_INET; //AF_INET:使用Internet 协议
((sockaddr_in*)&ser_addr)->sin_port = htons(3000); //服务器端口号3000
((sockaddr_in*)&ser_addr)->sin_addr.s_addr = inet_addr("127.0.0.1");//主机地址
//把套接字与地址绑定
bind(welcomesock,&ser_addr,sizeof(ser_addr));
//监听网络连接
listen(welcomesock,5); //监听连接:1--允许等待队列的长度
printf("等待客户连接!\n");
while(true)
{ int len;
struct sockaddr client_addr;
len = sizeof(client_addr);
//接受网络连接,生成新的套接字sersock标识这一连接
SOCKET connectsock = accept( welcomesock,&client_addr,&len );
//从等待队列中检取客户,如队列空则进程挂起
//如不空,则接受并生成新Socket以表示此连接,而原Socket继续等待新客户
if(connectsock==INVALID_SOCKET){
DWORD err = WSAGetLastError();
char txt[100];
sprintf(txt,"error when accept!---errno:%d",err);
printf(txt);
getch();
WSACleanup( ); //卸载Window Sockets DLL
return 0;
}
printf("有客户连接!\n等待用户信息\n");
len = recv ( connectsock,msg,1000,0 ); //接收请求行
/* if(len>=1000&&msg[len-1]!='\n'&&msg[len-2]!='\r')
{
printf("%d\n",len);
len=recv ( connectsock,msgtp,400,0 );
}*/
msg[len]=0; //char msg[1003]
printf(msg);
printf("\n");
char * p;
p = strtok(msg," "); //分割函数
if(strcmp(strupr(p),"GET")==0) //strupr()用于将字符串中的字符转换为小写 strcmp()函数:比较字符串(区分大小写)
{
p = strtok(NULL," ");
if(p[0]=='/')
{
p=p+1;
}
char * fname; //定义读入文件名
int flen,hlen;
int textflag=0;
fname=p;
ifstream fin(fname,ios::binary); //打开准备读取的文件
char sentence[2048]={0}; //定义文件读写的变量
if(fin.good()) //good()表示文件流是否正常,eof表示文件流是否到结束了
{
char tp[40];
fin.seekg(0,ios::end); //基地址为文件结束处,偏移地址为0,于是指针定位在文件结束处
flen= fin.tellg(); //tellg()函数不需要带参数,它返回当前定位指针的位置,也代表着输入流的大小。
fin.seekg(0,ios::beg); //表示输入流的开始位置
strcpy(sentence,"HTTP/1.1 200 OK\r\n");
strcat(sentence,"Content-Length: "); //把两个字符串连接起来
sprintf(tp,"%d",flen); //格式化输出字符串
strcat(sentence,tp);
strcat(sentence,"\r\nContent-Type: ");
if(endsWith(fname,".html")||endsWith(fname,".htm"))
{ strcpy(tp,"text/html");
textflag=1;
}
else
{ if(endsWith(fname,".txt"))
{ strcpy(tp,"text/plain"); textflag=1; }
else
{ if(endsWith(fname,".jpg"))
{ strcpy(tp,"image/jpeg\r\nAccept-Ranges:bytes"); }
else
{ if(endsWith(fname,".gif"))
{ strcpy(tp,"image/gif");}
}
}
}
strcat(sentence, tp);
strcat(sentence,"\r\n");
strcat(sentence,"\r\n");
printf(sentence);
int s;
s=send ( connectsock,sentence,strlen(sentence),0 ); //connectsock发送端套接字字符串描述 sentence存放应用程序要发送数据的缓冲区 strlen(sentence)要发送字节数
char ft[1024]={0};
int i,j;
if(textflag==0)
{
while(!fin.eof())
{
fin.read(ft,sizeof(ft));
send ( connectsock,ft,sizeof(ft),0 );
}
}
else
{
while(fin.getline(ft,1024))
{
send ( connectsock,ft,strlen(ft),0 );
}
}
}
else
printf("can not open the file!");
}
printf("\n\n已返回处理结果!\n");
//关闭套接字
closesocket(connectsock);
printf("\n已关闭与该客户的连接!\n");
printf("\n等待下一客户连接!\n");
}
closesocket(welcomesock);
WSACleanup( ); //卸载Window Sockets DLL
return 0;
}
bool InitSocket()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 0 );
//初始化Windows Sockets DLL,
err = WSAStartup( wVersionRequested, &wsaData );//加载Winsock DLL到内存
if ( err != 0 ) {
printf("没有Windows Socket动态库!\n");
getch();
return false;
}
if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0 ) {
printf("需要Windows Socket 2!\n");
getch();
WSACleanup( ); //非winsock 2.0时,卸载Window Sockets DLL
return false;
}
return true;
}
int endsWith(char s1[],char s2[])
{
int len1 = strlen(s1);
int len2 = strlen(s2);
int i=len1-1,j=len2-1;
if(len1
for(;i>=0&&j>=0;i--,j--){
if(s1[i]!=s2[j])return 0;
}
return 1;
}