天天看点

http协议户端下载流程

/**************************************************************************************

功能:http协议客户端网络下载测试

时间:2014-03-09

version : V1.0

说明:http协议客户端工作要点

1.创建socketbind本地socket,发起连接connetct ,完成tcp三次握手

2.向服务器发起http请求,即post或get动作,http协议请求格式见

  http协议规范

 3.读http响应,可以判定http 服务器和客户端是否通讯正常,如果失败,

 可以根据错误代码判定不成功原因。

 http 响应和http 错误代码见http协议部分

 4.http响应会返回内容的长度和内容类型,这个信息在在在线业务中是个

 非常有用的信息,比如流媒体是边看边下载,如果要计算流媒体长度

 只能从http响应读取。

***************************************************************************************/

#include <fcntl.h>

#include <sys/syscall.h>

#include <sys/mman.h>

#include <stdio.h>

#include <unistd.h>

#include <string.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <netdb.h>

#include <sys/types.h>

#include <errno.h>

#include <stdlib.h>

#define SERVER_PORT 5000

#define BUF_MASK 0x1ff

#define BUF_SIZE (188*7*64)

#define O_DIRECT 0x8000

void usage()

{

    printf("Usage: http_test_client: -d <srv-ip> -p <srv-port> -f <content-file> [-h -a -v]\n");

    printf("options are:\n");

    printf(" -d <srv-ip>   # IP address of HTTP Server (e.g. 192.168.1.110)\n");

    printf(" -p <srv-port> # Port of HTTP Server (e.g. 5000)\n");

    printf(" -f <file>     # url of stream; /data/videos prepended (e.g. portugal.mpg) \n");

    printf(" -m            # just leave content in memory, dont write to disk (default: write to file)\n");

    printf(" -v            # print periodic stats (default: no)\n");

    printf(" -h            # prints http_test_client usage\n");

    printf("\n");

}

double difftime1(struct timeval *start, struct timeval *stop)

{

double dt = 1000000.*(stop->tv_sec - start->tv_sec) + (stop->tv_usec - start->tv_usec);

return dt;

}

/* This function creates a TCP connection to server and returns the socket descriptor */

int TcpConnect(char *server, int port, int socket_type)

{

int sd,rc;

struct sockaddr_in localAddr, servAddr;

struct hostent *h;

printf("TCP - Connection to %s:%d ...\n",server, port);

h = gethostbyname(server);

if (h == NULL) {

perror("Unknown Host");

return (-EINVAL);

}

servAddr.sin_family = h->h_addrtype;

memcpy((char *) &servAddr.sin_addr.s_addr, h->h_addr_list[0],h->h_length);

servAddr.sin_port = htons(port);

/* Open Socket */

sd = socket(AF_INET, socket_type, 0);

if (sd<0) {

perror("Socket Open Err");

return -EINVAL;

}

localAddr.sin_family = AF_INET;

localAddr.sin_addr.s_addr = htonl(INADDR_ANY);

localAddr.sin_port = htons(0);

if (bind(sd,(struct sockaddr *) &localAddr, sizeof(localAddr))) {

perror("Socket Bind Err");

return -EINVAL;

}

/* Connect to server */

rc = connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr));

if (rc<0) {

perror("Connect Error: Server busy or unavailable:");

return -EBUSY;

}

printf("TCP: Connection Success\n");

return sd;

}

#define PKTS_PER_READ 64

#define MAX_BUFFER_SIZE (1316 * PKTS_PER_READ)

#define HTTP_POST_SIZE 2048

int main(int argc, char **argv)

{

char *post;

char *server = NULL;

char *fname = NULL;

int maxrate = 19;

int c;

int sd;

FILE *fp = NULL;

char *p;

char *rbuf;

int  port = 0;

ssize_t n;

unsigned char *buf, *xbuf;

ssize_t bytes = 0;

unsigned long total=0;

unsigned long count=0;

char tok;

ssize_t len;

double dt;

struct timeval start, stop;

int accel_socket = 0;   /* Use Standard Socket */

int dont_write_to_disk = 0;

int verbose = 0;

        char cname ='/';

    while ((c = getopt(argc, argv, "d:p:f:amvh")) != -1) {

        switch (c) {

        case 'd':

            server = optarg;

            break;

        case 'p':

            port = atoi(optarg);

            break;

        case 'f':

            fname = optarg;

            break;

        case 'a':

            accel_socket = 1;

            break;

        case 'm':

            dont_write_to_disk = 1;

            break;

        case 'v':

            verbose = 1;

            break;

        case 'h':

        default:

            usage();

            return -1;

        }

    }

if (port == 0 || server == NULL || fname == NULL) {

printf("Missing Args...\n");

usage();

exit(1);

}

printf("Server %s, Port %d, File %s, Maxrate %d\n",

server, port, fname, maxrate);

xbuf = (unsigned char *) malloc(BUF_SIZE + BUF_MASK);

rbuf = (char *) malloc(1024);

post = (char *) malloc(HTTP_POST_SIZE);

if (xbuf == NULL || rbuf == NULL || post == NULL) {

perror("malloc failure\n");

exit(-1);

}

buf = (unsigned char *) (((unsigned long)xbuf + BUF_MASK) & ~BUF_MASK);

/* Build HTTP Get Request */

n = snprintf(post, HTTP_POST_SIZE,

"GET /%s HTTP/1.1\r\n"

"Host: %s:%d\r\n"

"Rate: %d\r\n"

"PlaySpeed.dlna.org: speed=1\r\n"

"User-Agent: %s Test App\r\n"

"\r\n",

fname, server, port, maxrate, "STDSOCKET" );

printf("Sending HTTP Request:----->[\n%s]\n", post);

/* open file for writing */

if (!dont_write_to_disk) {

p=strrchr(fname,'/');

fname=p+1;

fp = fopen(fname,"wb");

if (!fp) {

perror("File open error:\n");

exit(-1);

}

}

/*TODO: enable O_DIRECT and test, need to change BUF_SIZE*/

/*fcntl(fileno(fp),F_SETFL,O_DIRECT);*/

/* Connect to Server */

sd = TcpConnect(server, port,  SOCK_STREAM);

if (sd < 0) {

printf("Connection to Server Failed, Exiting...\n");

exit(-1);

}

/* Send HTTP Get Request */

n = write(sd, post, strlen(post));

if ((unsigned)n != strlen(post)) {

printf("Failed to write HTTP Get Request: rc %d\n", n);

perror("write(): ");

exit(-1);

}

printf("Succesfully Send HTTP Get Request to to %s:%d\n", server, port);

usleep(10000);

/* Read HTTP Response */

memset(rbuf, 0, 1024);

if ( (n = read(sd, rbuf, 1024)) <= 0) {

printf("Failed to read HTTP Response: rc = %d\n", n);

perror("read(): ");

exit(-1);

}

    rbuf[n] = '\0'; 

/* Scan for end of HTTP header */

p = strstr(rbuf,"\r\n\r\n");

if(!p) {

printf("No HTTP Header\n");

len = 0;

p = rbuf;

tok = 0;

}

else {

p+=4;

tok = *p;

*p = 0;

len = strlen(rbuf);

}

printf("Total response len %d, payload len %d\n", n, n-len);

printf("HTTP Response: -----> [\n%s]\n", rbuf);

*p = tok;

/* write any data that was read part of the initial read */

if (n>len) {

if ( (total = write(fileno(fp), p, n - len)) <= 0 ) {

printf("Failed to write initial payload bytes (%lu)\n", total);

perror("write():\n");

exit(-1);

}

}

/* increase the recv buffer before starting to read the content */

//sockSetRecvParams(sd, accel_socket);

sleep(1);

gettimeofday(&start, NULL);

/* read data from network & write to the file */

while(1) {

if ( (n = read(sd, buf, BUF_SIZE)) <= 0) {

gettimeofday(&stop, NULL);

printf("read failed: n = %d\n", n);

perror("read(): ");

break;

}

gettimeofday(&stop, NULL);

if (dont_write_to_disk) {

            bytes = n;

goto after_write;

        }

if (((bytes = write(fileno(fp), buf, n)) <= 0) || bytes != n) {

printf("Failed to write payload bytes (%d)\n", bytes);

perror("write():\n");

break;

}

after_write:

dt = difftime1(&start, &stop);

total += bytes;

count++;

if (verbose && (count % 100) == 0) {

printf("[%10lu] Received %10lu Bytes in dt = %10.2fusec at rate %2.1f\n", 

count, total, dt, (total * 8. / dt));  

}

}

dt = difftime1(&start, &stop);

printf("Final stats: Received %10lu bytes to %s file in %10.1fusec at %2.1f rate\n", 

total, fname, dt, (total * 8. / dt));

fclose(fp);

free(xbuf);

free(rbuf);

    free(post);

return 0;

}

/********************************************************************************

比如下载一个MP3文件过程如下:

root@ubuntu:/home/hfl/hflsamb/network# ./http_test_client -d 192.168.1.108 -p 80 -f /myserver/wy.mp3 -v   

Server 192.168.1.108, Port 80, File /myserver/wy.mp3, Maxrate 19

Sending HTTP Request:----->[

GET //myserver/wy.mp3 HTTP/1.1

Host: 192.168.1.108:80

Rate: 19

PlaySpeed.dlna.org: speed=1

User-Agent: STDSOCKET Test App

]

TCP - Connection to 192.168.1.108:80 ...

TCP: Connection Success

Succesfully Send HTTP Get Request to to 192.168.1.108:80

Total response len 1024, payload len 773

HTTP Response: -----> [

HTTP/1.1 200 OK

Date: Sun, 09 Mar 2014 10:45:55 GMT

Server: Apache/2.2.22 (Win32)

Last-Modified: Tue, 19 Apr 2011 13:10:17 GMT

ETag: "560000000302d3-40275b-4a1453ac09c0f"

Accept-Ranges: bytes

Content-Length: 4204379

Content-Type: audio/mpeg

]

[       100] Received    3329486 Bytes in dt = 1388794.00usec at rate 19.2

read failed: n = 0

read(): : Success

Final stats: Received    4204379 bytes to wy.mp3 file in  6998282.0usec at 4.8 rate

root@ubuntu:/home/hfl/hflsamb/network# 

*********************************************************************************/