一个简单的http下载程序

王朝other·作者佚名  2006-01-10
宽屏版  字体: |||超大  

最近研究了一下http协议,用C++在linux下写了一个简单的http下载程序,程序的功能很简单,在终端输入文件所在网址,程序会单线程从服务器上下载该文件到本地。程序里面涉及了socket编程、http协议、二进制文件的写入。有兴趣的兄弟可以随便看看,玩具而已,大家一起玩玩了。

对于Http协议不是很了解的兄弟,可以去http://biz.chinabyte.com/209/2151709.shtml 看看,对于初学者,这篇文章是相当不错的。

所有源码可以到http://www.kunxu.com/kun/download/code/C/http_client.rar 下载

下面贴出来的是文件的源码:

CSocket.h:

#ifndef __CSOCKET_H__

#define __CSOCKET_H__

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <stdarg.h>

#include <string.h>

#include <errno.h>

#include <netdb.h>

#include <fcntl.h>

#include <sys/time.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <string>

#include <iostream>

using namespace std;

typedef enum socket_type { SERVER_TYPE = 0, CLIENT_TYPE } s_type;

typedef enum socket_state{ CONN_ERROR = -1, CONN_OK = 0, CONN_WAIT = 1 } s_state;

class Sock_instance

{

public:

Sock_instance(string hostname, unsigned port, s_type type);

~Sock_instance();

bool Connect();

int fd();

s_state state();

bool Send(string msg);

int Receive();

void Close();

unsigned char* data() const;

int datalen() const;

string http_head() const;

private:

string _hostname;

unsigned _port;

int _fd;

s_state _state;

s_type _type;

unsigned char *_data;

int _datalen;

string _http_head;

};

#endif

CSocket.cpp:

#include "CSocket.h"

Sock_instance::Sock_instance(string hostname, unsigned port, s_type type)

: _hostname( hostname ),

_port( port ),

_fd( 0 ),

_state( CONN_ERROR ),

_type( type )

{

_datalen = 0;

_data = new unsigned char[1024*1024];

}

Sock_instance::~Sock_instance()

{

delete[] _data;

}

bool Sock_instance::Connect()

{

if( _type == SERVER_TYPE )

{

cout << "The socket is a server, don't use conncet!" << endl;

return false;

}

struct sockaddr_in peer;

int fd;

bzero( &peer, sizeof(peer) );

peer.sin_family = AF_INET;

struct hostent *hp = gethostbyname( _hostname.c_str() );

if ( hp == NULL )

{

cout << "unknow host: " << _hostname << endl;

return false;

}

peer.sin_addr = *( ( struct in_addr * )hp->h_addr );

peer.sin_port = htons(_port);

cout << "conncet to " << inet_ntoa(peer.sin_addr) << ": " << ntohs( peer.sin_port ) << endl;

fd = socket( AF_INET, SOCK_STREAM, 0 );

if ( fd < 0 )

{

cout << "socket call failed" << endl;

return false;

}

if( connect( fd, (struct sockaddr *)&peer, sizeof( peer ) ) )

{

cout << errno << "connect failed" << endl;

_state = CONN_ERROR;

close( fd );

return false;

}

_state = CONN_OK;

_fd = fd;

return true;

}

s_state Sock_instance::state()

{

return _state;

}

int Sock_instance::fd()

{

return _fd;

}

bool Sock_instance::Send(string msg)

{

if( state() != CONN_OK )

{

cout << "the socket is not ok" << endl;

return false;

}

int rc;

if((rc = send(_fd, msg.c_str(), msg.size(), 0)) == -1)

{

if((errno != EWOULDBLOCK) && (errno != EAGAIN))

{

_state = CONN_ERROR;

return false;

}

}

return true;

}

int Sock_instance::Receive()

{

int rc;

char buf[BUFSIZ];

char *p_buf = buf;

static bool b_readhead = true;

bzero(buf, BUFSIZ);

if((rc = recv( _fd, buf, BUFSIZ - 1, 0 )) < 0 )

{

cout << "recive error" << endl;

_state = CONN_WAIT;

Close();

}

else if( rc == 0 )

{

cout << "server teminated" << endl;

_state = CONN_WAIT;

Close();

}

else

{

//read HTTP head

int ix = 0;

while( b_readhead )

{

// 2 0D 0A just for head end

if( ix >= rc )

break;

if( buf[ix] == 13 && buf[ix+1] == 10 && buf[ix+2] == 13 && buf[ix+3] == 10 )

{

b_readhead = false;

char *p = new char[ix+5];

memset( p, 0, ix+5 );

memcpy( p, buf, ix+5 );

p_buf += ix + 5;

_http_head = p;

delete[] p;

cout << _http_head << endl;

break;

}

ix ++;

}

//copy data to _data

if( ix != 0 && ix < rc )

{

//this buf has head so data begin with buf+ix+4

memcpy( _data+_datalen, buf+ix+4, rc-ix-4 );

_datalen += rc-ix-4;

}

else

{

memcpy( _data+_datalen, buf, rc );

_datalen += rc;

}

}

return rc;

}

inline void Sock_instance::Close()

{

close( _fd );

}

//string Sock_instance::data() const

unsigned char * Sock_instance::data() const

{

return _data;

}

int Sock_instance::datalen() const

{

return _datalen;

}

string Sock_instance::http_head() const

{

return _http_head;

}

http_main.cpp:

#include "CSocket.h"

#include <fstream>

int main()

{

string word;

string filename;

string hostname;

int pos1 = 0;

int pos2 = 0;

cout << "enter the host name" << endl;

cin >> word;

//bulid the query for http

string quest = "GET ";

quest += word;

quest += " HTTP/1.0\r\n";

quest += "User-agent:Mozilla/4.0\r\n";

quest += "Accept-language:zh-cn\r\n\r\n";

//get the hostname and filename from the word

string str_http = "http://";

pos1 = word.find_first_of (str_http, 0);

pos2 = word.find_first_of ("/", pos1+7);

hostname = word.substr( pos1+7, pos2-pos1-7 );

pos1 = word.find_last_of( "/", word.size() );

filename = word.substr( pos1+1, word.size()-pos1-1 );

cout << "filename: " << filename << endl;

cout << "hostname: " << hostname << endl;

//use the hostname and port 80 to connect

Sock_instance s_client( hostname, 80, CLIENT_TYPE );

if( !s_client.Connect() )

{

cout << "connect error" << endl;

return -1;

}

//send the http query to the host

cout << "connect is ok!" << endl;

if( !s_client.Send(quest) )

{

cout << "send is error!" << endl;

return -1;

}

//recieve all the file from the hsot

while( s_client.Receive() > 0 )

{

}

//write the binary data which is recieved on the file

FILE *fp = fopen( filename.c_str(), "wb" );

fwrite( s_client.data(), sizeof( unsigned char ), s_client.datalen(), fp );

fclose( fp );

return 0;

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
© 2005- 王朝网络 版权所有