@1405010312
2016-12-02T04:13:39.000000Z
字数 3553
阅读 495
web服务器
其响应客户端的请求后就立马断开连接,也就是说服务端不会维持客户端状态.所以其又称为"无状态的Stateless协议"由于这个特性,web编程通常用Cookie和Session技术.
请求消息结构:其由消息行,消息头,消息体构成.请求行含有请求方式信息(GET和POST),请求行只有一行.消息头包含发送请求的浏览器信息,用户认证信息等附加信息.消息体与消息头中有一行空行用来区分消息头和消息体.
- 获取请求消息,并相应提取请求方式和文件的绝对路径,通过绝对路径打开文件,然后传送给浏览器.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <process.h>
#define BUF_SIZE 2048
#define BUF_SMALL 100
unsigned WINAPI RequestHandler(void* arg);
char* ContentType(char* file);
void SendData(SOCKET sock, char* ct, char* fileName);
void SendErrorMSG(SOCKET sock);
void ErrorHandling(char *message);
int main(int argc, char *argv[])
{
WSADATA wsaData;
SOCKET hServSock, hClntSock;
SOCKADDR_IN servAdr, clntAdr;
HANDLE hThread;
DWORD dwThreadID;
int clntAdrSize;
if(argc!=2) {
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
if(WSAStartup(MAKEWORD(2, 2), &wsaData)!=0)
ErrorHandling("WSAStartup() error!");
hServSock=socket(PF_INET, SOCK_STREAM, 0);
memset(&servAdr, 0, sizeof(servAdr));
servAdr.sin_family=AF_INET;
servAdr.sin_addr.s_addr=htonl(INADDR_ANY);
servAdr.sin_port=htons(atoi(argv[1]));
if(bind(hServSock, (SOCKADDR*) &servAdr, sizeof(servAdr))==SOCKET_ERROR)
ErrorHandling("bind() error");
if(listen(hServSock, 5)==SOCKET_ERROR)
ErrorHandling("listen() error");
while(1)
{
clntAdrSize=sizeof(clntAdr);
hClntSock=accept(hServSock, (SOCKADDR*)&clntAdr, &clntAdrSize);
printf("Connection Request : %s:%d\n",
inet_ntoa(clntAdr.sin_addr), ntohs(clntAdr.sin_port));
hThread=(HANDLE)_beginthreadex(
NULL, 0, RequestHandler, (void*)hClntSock, 0, (unsigned *)&dwThreadID);
}
closesocket(hServSock);
WSACleanup();
return 0;
}
unsigned WINAPI RequestHandler(void *arg)
{
SOCKET hClntSock=(SOCKET)arg;
char buf[BUF_SIZE];
char method[BUF_SMALL];
char ct[BUF_SMALL];
char fileName[BUF_SMALL];
recv(hClntSock, buf, BUF_SIZE, 0);
if(strstr(buf, "HTTP/")==NULL)
{
SendErrorMSG(hClntSock);
closesocket(hClntSock);
return 1;
}
strcpy(method, strtok(buf, "/"));
if(strcmp(method, "GET "))
SendErrorMSG(hClntSock);
strcpy(fileName, strtok(NULL, " "));
strcpy(ct, ContentType(fileName));
SendData(hClntSock, ct, fileName);
return 0;
}
void SendData(SOCKET sock, char* ct, char* fileName)
{
char protocol[]="HTTP/1.0 200 OK\r\n";
char servName[]="Server:simple web server\r\n";
char cntLen[]="Content-length:2048\r\n";
char cntType[BUF_SMALL];
char buf[BUF_SIZE];
FILE* sendFile;
sprintf(cntType, "Content-type:%s\r\n\r\n", ct);
if((sendFile=fopen(fileName, "r"))==NULL)
{
SendErrorMSG(sock);
return;
}
send(sock, protocol, strlen(protocol), 0);
send(sock, servName, strlen(servName), 0);
send(sock, cntLen, strlen(cntLen), 0);
send(sock, cntType, strlen(cntType), 0);
while(fgets(buf, BUF_SIZE, sendFile)!=NULL)
send(sock, buf, strlen(buf), 0);
closesocket(sock);
}
void SendErrorMSG(SOCKET sock)
{
char protocol[]="HTTP/1.0 400 Bad Request\r\n";
char servName[]="Server:simple web server\r\n";
char cntLen[]="Content-length:2048\r\n";
char cntType[]="Content-type:text/html\r\n\r\n";
char content[]="<html><head><title>NETWORK</title></head>"
"<body><font size=+5><br>发生错误!"
"</font></body></html>";
send(sock, protocol, strlen(protocol), 0);
send(sock, servName, strlen(servName), 0);
send(sock, cntLen, strlen(cntLen), 0);
send(sock, cntType, strlen(cntType), 0);
send(sock, content, strlen(content), 0);
closesocket(sock);
}
char* ContentType(char* file)
{
char extension[BUF_SMALL];
char fileName[BUF_SMALL];
strcpy(fileName, file);
strtok(fileName, ".");
strcpy(extension, strtok(NULL, "."));
if(!strcmp(extension, "html")||!strcmp(extension, "htm"))
return "text/html";
else
return "text/plain";
}
void ErrorHandling(char* message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
4.实验结果:
5.实验总结
感觉这次学到了很多东西,主要是知道了HTTP协议,并懂得了如何初步处理它.在实验过程中也遇到了各种各样的问题,比如消息行的处理等.这次没有写图形界面了,感觉好难写不出来.还有就是由于HTTP是无状态的协议,所以最好是来个while循环发送消息,不然很容易看不到内容.