这里接着介绍上篇的内容:
本来构造响应报文应该在上一篇一起介绍的,东西比较多就留到这里说了。
这里我只弄了最基础简单的5行,还有非常多功能是没有的,有兴趣的可能去查看http/1.1的RFC文档,现在都有中文版pdf的了,或者也可以使用curl命令先看看apache服务器构造了哪些:
下面只说有实现的,其他如Cache=Control等可以去查上面说的RFC文档
首先第一行:Connection:keep-alive
持续连接,默认http/1.1就是持续的,可以不用发这个
第2行:Date:…
时间,也不是必须的,强调一下,这里的时间是你收到请求响应的服务器时间,并不是显示到你浏览器的时间,因为传输过程中还是会有一些时延的
第3行:Server:…
也不是必须的,比如apache的就会写成:Apache/2.4.10,可以改成自己喜欢的内容
第4行:Content-Length: 95
发送实体的长度,即这里文件1.html的长度
第5行:Content-Type:text/html
用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件;如果这里你没有指定类型,比如这时传输一个html文档,360浏览器可能就不会显示出来而是直接下载该文档了;
Content-Type有很多类型,详见http/1.1 RFC文档
下面是简单客户端的C代码:
#include
#include
#include
#pragma comment(lib,"Ws2_32.lib")
#define BUF_LENGTH 1024
#define USER_ERROR -1
int main()
{
WSADATA wsData;
SOCKET sClient; //客户端套接字
struct sockaddr_in ser; //服务器进程地址
char send_buf[BUF_LENGTH]; //发送缓存
char recv_buf[BUF_LENGTH]; //接收缓存
int iSend, iRecv; //接收数据和发送数据长度
//第一步:加载协议栈
if (WSAStartup(MAKEWORD(2,2),&wsData)!=0)
{
printf("Failed to load Winsock.\n");
return USER_ERROR;
}
//创建服务器地址
ser.sin_family=AF_INET;
ser.sin_port=htons(80); //服务器端口号
ser.sin_addr.s_addr=inet_addr("127.0.0.1"); //服务器IP地址
//第二步:创建流套接字,运输层采用TCP协议
sClient=socket(AF_INET,SOCK_STREAM,0);
if (sClient==INVALID_SOCKET)
{
printf("socket() Failed:%d\n",WSAGetLastError());
return USER_ERROR;
}
//第三步:通过创建的套接字向相应的服务器发起连接请求
if (connect(sClient,(struct sockaddr*)&ser,sizeof(ser))==INVALID_SOCKET)
{
printf("connet() Failed:%d\n",WSAGetLastError());
return USER_ERROR;
}
else //连接成功
{
//第四步:通过套接字发数据
printf("input data to send:\n");
memset(send_buf,0,sizeof(send_buf)); //缓存清0
gets(send_buf);
iSend=send(sClient,send_buf,sizeof(send_buf),0); //通过套接字发送数据给服务器
if (iSend==SOCKET_ERROR) //发送不成功
{
printf("send() Failed:%d\n",WSAGetLastError());
return USER_ERROR;
}
else
printf("send success\n"); //发送成功
printf("recv data from server: \n");
while(1)
{
memset(recv_buf,0,sizeof(recv_buf)); //缓存清0
iRecv=recv(sClient,recv_buf,sizeof(recv_buf),0);
if(strcmp(recv_buf,"") == 0) // 接收缓存为空则表示接受完毕,退出
break;
if (iRecv ==SOCKET_ERROR) //接收错误
{
printf("recv() Failed:%d\n",WSAGetLastError());
return USER_ERROR;
}
else
printf("%s\n",recv_buf); // 打印接收缓存
}
}
//第五步:释放该套接字,断开连接
closesocket(sClient);
WSACleanup();
return 0;
}
首先运行上次的web服务器,然后再运行客户端:
例1、输入:HEAD /1.html HTTP/1.1 表示使用HEAD方法获取首部
例2、输入:HEAD /1.htmlxxx HTTP/1.1