/************************************************************************************** 功能:http协议客户端网络下载测试 时间:2014-03-09 version : V1.0 说明:http协议客户端工作要点 1.创建socketbind本地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# *********************************************************************************/
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有