基于http传输(二)

来源:互联网 发布:手机工作证制作软件 编辑:程序博客网 时间:2024/04/28 19:39

文件传输

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 0
原创粉丝点击