这里接着介绍上篇的内容:
本来构造响应报文应该在上一篇一起介绍的,东西比较多就留到这里说了。 


C实现简单web服务器-2(windows)_C、web服务器 

这里我只弄了最基础简单的5行,还有非常多功能是没有的,有兴趣的可能去查看http/1.1的RFC文档,现在都有中文版pdf的了,或者也可以使用curl命令先看看apache服务器构造了哪些: 


C实现简单web服务器-2(windows)_C、web服务器_02


下面只说有实现的,其他如Cache缓存控制等可以去查上面说的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 <Winsock2.h>
#include <stdio.h>
#include<string.h>
#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方法获取首部
C实现简单web服务器-2(windows)_C、web服务器_03


例2、输入:HEAD /1.htmlxxx HTTP/1.1
C实现简单web服务器-2(windows)_C、web服务器_04


例3、输入:GET /1.html HTTP/1.1  返回首部和实体,即这里的文件内容
C实现简单web服务器-2(windows)_C、web服务器_05


例4、输入:GET /1.htmlxxx HTTP/1.1
C实现简单web服务器-2(windows)_C、web服务器_06