用HTTP协议下载一个MP3文件

时间:2021-01-19 10:18:31

在visual studio上调试通过的,这个只是一个示例,还有很多不完善的细节(鲁棒性)需要考虑。

主要流程:

1)创建一个TCP连接
2)发送一个HTTP GET命令
3)读取一段数据,解析出Content-Length字段,找到MP3文件的长度
4)循环读取数据,直到读取到的数据量大于等于MP3文件的长度

#include "stdafx.h"
#include <Winsock2.h>
#include <iostream>
#include <cstdio>

#pragma comment(lib, "ws2_32.lib")

int _tmain(int argc, _TCHAR* argv[])
{

const char CTL_STR[] = "Content-Length";


// 加载socket动态链接库(dll)
WORD wVersionRequested;
WSADATA wsaData; // 这结构是用于接收Wjndows Socket的结构信息的
int err;

FILE *hFile = fopen("out.mp3","wb");

wVersionRequested = MAKEWORD( 1, 1 ); // 请求1.1版本的WinSock库

err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return -1; // 返回值为零的时候是表示成功申请WSAStartup
}

if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) {
// 检查这个低字节是不是1,高字节是不是1以确定是否我们所请求的1.1版本
// 否则的话,调用WSACleanup()清除信息,结束函数
WSACleanup( );
return -1;
}

// 创建socket操作,建立流式套接字,返回套接字号sockClient
// SOCKET socket(int af, int type, int protocol);
// 第一个参数,指定地址簇(TCP/IP只能是AF_INET,也可写成PF_INET)
// 第二个,选择套接字的类型(流式套接字),第三个,特定地址家族相关协议(0为自动)
SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);

// 将套接字sockClient与远程主机相连
// int connect( SOCKET s, const struct sockaddr* name, int namelen);
// 第一个参数:需要进行连接操作的套接字
// 第二个参数:设定所需要连接的地址信息
// 第三个参数:地址的长度
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = inet_addr("61.155.41.53"); ;
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(80);
connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));


char cmd_str[] = "GET /speeches/obama/Obama%202017-01-13%20Weekly%20Address%20-%20The%20Honor%20of%20Serving%20You%20as%20President.mp3 HTTP/1.1\r\nHOST:www.listeningexpress.com\r\n\r\n";
//通过 TCP 连接,发送 HTTP GET命令
send(sockClient, cmd_str, strlen(cmd_str), 0);

char recvBuf[3001];
int iResult = 0 ;
int i;
int j;

iResult = recv(sockClient, recvBuf, 3000, 0);

char len_str[100];


//to find the "Content-Length"
for(i=0;i<iResult;i++)
{


for( j =0; j<strlen(CTL_STR); j++)
if(recvBuf[i+j] != CTL_STR[j])
break;

if(j == strlen(CTL_STR) )
{
i += j;
break;
}
}

//to get the "Content-Length"
j=0;
for(;i<iResult;i++)
{
if( recvBuf[i] >= '0' && recvBuf[i] <= '9')
{
len_str[j] = recvBuf[i];
len_str[j+1] = 0;
j++;
}
if( (recvBuf[i] == 0x0d) && (recvBuf[i+1] == 0x0a))
break;
}
int length_ctr = atoi(len_str);

//to find the END of Header
for(i=0;i<iResult;i++)
{
if( (recvBuf[i] == 0x0d) && (recvBuf[i+1] == 0x0a) && (recvBuf[i+2] == 0x0d) && (recvBuf[i+3] == 0x0a) )
break;
}

int current_len = iResult - i - 4 ;

fwrite(&recvBuf[i+4], 1, current_len, hFile);

i=1;
do{


memset(recvBuf,0,3001);
iResult = recv(sockClient, recvBuf, 3000, 0);
if(iResult > 0)
{
fwrite(recvBuf, 1, iResult, hFile);
current_len+= iResult;
}
else
printf("no data \n");



if( current_len >= length_ctr )
break;

i++;

}while(iResult > 0);

printf("End linking...\n");
closesocket(sockClient);
WSACleanup(); // 终止对套接字库的使用

fclose(hFile);

printf("\n");
system("pause");

return 0;
}