基于http传输(二)

文件传输

http传输的核心还是基于tcp/ip协议传输,服务器端启动,客户端通过指定的地址以及端口寻找服务器,然后进行连接;在windows下我们主要还是通过socket套接字建立连接:

/*服务器端*/
WSAStartup(MAKEWORD(2, 0), &wsa_data); /* 初始化 WinSock 资源 */

    srv_soc = socket(AF_INET, SOCK_STREAM, 0); /* 创建 socket */
    if (srv_soc == INVALID_SOCKET)
    {
        printf("[Web] socket() Fails, error = %d\n", WSAGetLastError());
        return -1;
    }

    /* 服务器地址 */
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    result = bind(srv_soc, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
    if (result == SOCKET_ERROR) /* 绑定失败 */
    {
        closesocket(srv_soc);
        printf("[Web] Fail to bind, error = %d\n", WSAGetLastError());
        return -1;
    }

    result = listen(srv_soc, SOMAXCONN);
    printf("[Web] The server is running ... ...\n");
WSAStartup(MAKEWORD(2, 0), &wsa_data); /* 初始化 WinSock 资源 */

    addr = inet_addr(host);
    if (addr == INADDR_NONE)
    {
        host_ent = gethostbyname(host);
        if (!host_ent)
        {
            printf("[Web] invalid host\n");
            return -1;
        }

        memcpy(&addr, host_ent->h_addr_list[0], host_ent->h_length);
    }

    /* 客户端 */
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port);
    serv_addr.sin_addr.s_addr = addr;

    http_sock = socket(AF_INET, SOCK_STREAM, 0); /* 创建 socket */
    result = connect(http_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
    if (result == SOCKET_ERROR) /* 连接失败 */
    {
        closesocket(http_sock);
        printf("[Web] fail to connect, error = %d\n", WSAGetLastError());
        return -1;
    }

紧接着client要发送http消息头让服务器处理:

/* 发送 HTTP 请求 */
    send_len = sprintf(cmd_buf, http_req_hdr_tmpl, argv[1], host, port, flag);
    result = send(http_sock, cmd_buf, send_len, 0);
    if (result == SOCKET_ERROR) /* 发送失败 */
    {
        printf("[Web] fail to send, error = %d\n", WSAGetLastError());
        return -1;
    }

可以看到,我们使用了send()函数,其中cmd_buf是消息头内容。此时服务器接收对应信息:

acpt_soc = accept(srv_soc, (struct sockaddr *) &from_addr, &from_len);
        if (acpt_soc == INVALID_SOCKET) /* 接受失败 */
        {
            printf("[Web] Fail to accept, error = %d\n", WSAGetLastError());
            break;
        }

        printf("[Web] Accepted address:[%s], port:[%d]\n",
            inet_ntoa(from_addr.sin_addr), ntohs(from_addr.sin_port));

        recv_len = recv(acpt_soc, cmd_buf, HTTP_BUF_SIZE, 0);
        if (recv_len == SOCKET_ERROR) /* 接收失败 */
        {
            closesocket(acpt_soc);
            printf("[Web] Fail to recv, error = %d\n", WSAGetLastError());
            break;
        }

我们用accept()函数接受连接建立,然后recv()函数接收客户端的内容。服务器端接收到控制指令后打开对应的文件并读取,回传:

res_file = fopen(filename, "rb+"); /* 用二进制格式打开文件 */
    if (res_file == NULL)
    {
        printf("[Web] The file [%s] is not existed\n", filename);
        return 0;
    }

    fseek(res_file, 0, SEEK_END);
    file_len = ftell(res_file);
    fseek(res_file, 0, SEEK_SET);

    type = http_get_type_by_suffix(suffix); /* 文件对应的 Content-Type */
    if (type == NULL)
    {
        printf("[Web] There is not the related content type\n");
        return 0;
    }

    do /* 发送文件, HTTP 的消息体 */
    {
        read_len = fread(data_buf, sizeof(char), HTTP_BUF_SIZE, res_file);

        if (read_len > 0)
        {
            send_len = send(soc, data_buf, read_len, 0);
            file_len -= read_len;
        }
    } while ((read_len > 0) && (file_len > 0));

    fclose(res_file);
    return 1;

以此类推,上传文件基本操作也只是逆操作。

到这里,一个简易的上传下载文件项目已经完成;在这里应该注意的是:定义的消息体变量buf应设为外部变量,若只是局部变量,当索要内存过大时,压栈会stack overflow,而外部变量主要压入堆里。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值