linux C 根据域名获取http响应报文,C语言HTTP请求GET。

jackxiang 2010-10-26 13:28 | |
今天没事写了个小demo, 根据域名获取http响应报文, 程序也不是很完善
其实主要是要练习一下非阻塞I/O处理.

上代码:

/*
* Author: looyao
*/

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

static int set_fl(int fd, int flags)
{
int val;

if ((val = fcntl(fd,F_GETFL,0)) < 0) {
printf("fcntl F_GETFL error\n");
return -1;
}

val |= flags;

if (fcntl(fd,F_SETFL,val) < 0) {
printf("fcntl F_SETFL error\n");
return -1;
}

return 0;
}

void timeout()
{
printf("time out\n");
exit(0);
}

int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
struct hostent *host;
char *msg = strdup("GET / HTTP/1.1\r\nHOST: ");
char rbuf[32], res_header[1024];
char *host_ip, *ptr, *pos;
int ntowrite, nwrite, nread, nread_res_header = 0, content_length, nread_content_length = 0;

signal(SIGALRM, timeout);

if (argc < 2) {
printf("请输入域名参数\n");
exit(0);
} else if (argc > 2) {
printf("输入的参数过多\n");
exit(0);
}

msg = realloc(msg, strlen(msg) + strlen(argv[1]) + sizeof("\r\n\r\n"));
sprintf(msg + strlen(msg), "%s\r\n\r\n", argv[1]);

sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket");
exit(0);
}

host = gethostbyname(argv[1]);
if (host == NULL) {
printf("无法获取此域名IP\n");
goto END;
}

host_ip = inet_ntoa(*((struct in_addr *)host->h_addr));

bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(80);
inet_pton(AF_INET, host_ip, &servaddr.sin_addr);
if( connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
perror("connect");
exit(0);
}

if (set_fl(sockfd, O_NONBLOCK) < 0) {
printf("set nonblock error");
goto END;
}

ntowrite = strlen(msg);
ptr = msg;
alarm(10);
while (ntowrite > 0) {
nwrite = write(sockfd, ptr, ntowrite);
if (nwrite <= 0) {
perror("write:");
goto END;
}
ptr += nwrite;
ntowrite -= nwrite;
}
alarm(0);

/* read response header */
ptr = res_header;
alarm(10);
while (1) {
errno = 0;
nread = read(sockfd, ptr, sizeof(res_header) - nread_res_header);
if(nread < 0){
if(errno == EAGAIN){
continue;
}
perror("read");
goto END;
}
nread_res_header += nread;
ptr += nread;
if((pos = strstr(res_header, "\r\n\r\n")) != NULL || nread_res_header == sizeof(res_header)){
break;
}
}
alarm(0);

if (!(pos = strstr(res_header, "Content-Length:"))) {
printf("响应报文错误");
goto END;
} else {
pos += 16;
if (!(ptr = strstr(pos, "\r\n"))) {
printf("响应报文错误");
goto END;
}
char buf[10];
snprintf(buf, (ptr - pos) > 10 ? 10 : (ptr - pos) + 1, "%s", pos);
content_length = atoi(buf);
}

write(STDOUT_FILENO, res_header, nread_res_header);
if ((pos = strstr(ptr, "\r\n\r\n"))) {
pos += 4;
nread_content_length = nread_res_header - (pos - res_header);
} else {
/* 此处有bug, 如果响应头很长, 没有读到\r\n\r\n, 但是, 先这样吧 :D */
goto END;
}

alarm(10);
while (1) {
errno = 0;
memset(rbuf, 0, sizeof(rbuf));
nread = read(sockfd, rbuf, sizeof(rbuf));
if (nread < 0) {
if (errno == EAGAIN) {
continue;
}
perror("read");
goto END;
}
write(STDOUT_FILENO, rbuf, nread);
nread_content_length += nread;
if (nread_content_length >= content_length){
break;
}
}
alarm(0);

END:
close(sockfd);
free(msg);
return 0;
}


编译后运行 ./demo www.baidu.com
响应的报文如下:
HTTP/1.1 200 OK
Date: Thu, 29 Apr 2010 08:57:48 GMT
Server: BWS/1.0
Content-Length: 3521
Content-Type: text/html;charset=gb2312
Cache-Control: private
Expires: Thu, 29 Apr 2010 08:57:48 GMT
Set-Cookie: BAIDUID=4573491A3ED9E0B16CA37586CFB9460E:FG=1; expires=Thu, 29-Apr-40 08:57:48 GMT; path=/; domain=.baidu.com
P3P: CP=" OTI DSP COR IVA OUR IND COM "

<!doctype html><html><head><meta http-equiv="Content-Type" content="text/html;charset=gb2312"><title>百度一下,你就知道      </title><style>body{font:12px arial;text-align:center;background:#fff}body,p,form{margin:0;padding:0}body,form,#lg{position:relative}td{text-align:left}img{border:0}a{color:#00c}a:active{color:#f60}#u{padding:7px 10px 3px 0;text-align:right}#m{width:650px;margin:0 auto}#nv{font-size:16px;margin:0 0 4px -32px}#nv a,#nv b,#su,#lk{font-size:14px}#lg{margin:-17px 0 9px}#fm{padding-left:111px;text-align:left}#kw{width:391px;line-height:16px;padding:3px 1px;margin:0 6px 0 0;font:16px arial}#su{width:78px;height:28px;line-height:24px}#kw,#su{vertical-align:middle}#lk{margin:33px 0}#lk span{font:14px "宋体"}#lm{height:60px}#lh{margin:16px 0 5px;font:12px "宋体"}#lh a{font:12px arial}#hp{position:absolute;line-height:14px;margin:0 0 0 6px;top:-1px;*top:2px}#cp,#cp a{color:#77c}</style></head>
<body><p id="u"><a href="http://passport.baidu.com/?login&tpl=mn">登录</a></p><div id="m"><p id="lg"><img src="http://www.baidu.com/img/baidu_logo.gif" width="270" height="129" usemap="#mp"></p><p id="nv"><a href="http://news.baidu.com">新&nbsp;闻</a> <b>网&nbsp;页</b> <a href="http://tieba.baidu.com">贴&nbsp;吧</a> <a href="http://zhidao.baidu.com">知&nbsp;道</a> <a href="http://mp3.baidu.com">MP3</a> <a href="http://image.baidu.com">图&nbsp;片</a> <a href="http://video.baidu.com">视&nbsp;频</a> <a href="http://map.baidu.com">地&nbsp;图</a></p><div id="fm"><form name="f" action="s"><input type="text" name="wd" id="kw" maxlength="100"><input type="submit" value="百度一下" id="su"><span id="hp"><a href="/gaoji/preferences.html">设置</a><br><a href="/gaoji/advanced.html">高级</a></span></form></div>
<p id="lk"><a href="http://hi.baidu.com">空间</a> <a href="http://baike.baidu.com">百科</a> <a href="http://www.hao123.com">hao123</a><span> | <a href="/more/">更多&gt;&gt;</a></span></p><p id="lm"></p><p><a id="st" onClick="this.style.behavior='url(#default#homepage)';this.setHomePage('http://www.baidu.com')" href="http://utility.baidu.com/traf/click.php?id=215&url=http://www.baidu.com">把百度设为主页</a></p><p id="lh"><a href="http://e.baidu.com/?refer=888">加入百度推广</a> | <a href="http://top.baidu.com">搜索风云榜</a> | <a href="http://home.baidu.com">关于百度</a> | <a href="http://ir.baidu.com">About Baidu</a></p><p id="cp">&copy;2010 Baidu <a href="/duty/">使用百度前必读</a> <a href="http://www.miibeian.gov.cn" target="_blank">京ICP证030173号</a> <img src="http://gimg.baidu.com/img/gs.gif"></p></div><map name="mp"><area shape="rect" coords="43,22,227,91" href="http://hi.baidu.com/baidu/" target="_blank" title="点此进入 百度的空间"></map></body>
<script>var w=window,d=document,n=navigator,k=d.f.wd,a=d.getElementById("nv").getElementsByTagName("a");if(n.userAgent.indexOf("MSIE")==-1||window.opera){d.getElementById("st").style.display="none"};for(var i=0;i<a.length;i++){a[i].onclick=function(){if(k.value.length>0){var o=this,h=o.href,q=encodeURIComponent(k.value);if(h.indexOf("q=")!=-1){o.href=h.replace(/q=[^&$]*/,"q="+q)}else{this.href+="?q="+q}}}};(function(){if(/q=([^&]+)/.test(location.search)){k.value=decodeURIComponent(RegExp.$1)}})();if(n.cookieEnabled&&!/sug?=0/.test(d.cookie)){d.write('<script src=http://www.baidu.com/js/bdsug.js?v=1.0.3.0><\/script>')};if(w.attachEvent){w.attachEvent("onload",function(){k.focus();})}else{w.addEventListener('load',function(){k.focus()},true)};w.onunload=function(){}</script></html><!--ae75535d4a224623-->


非阻塞要不断的轮询, 浪费了CPU时间, 但是说与使用select机制相比, 到底那个机制更快,
也需要看情况, 我会继续试验.
对于read的结束条件, 具体看通信的协议.
http协议主要是看Content-Length, 还有一种是Transfer-Encoding: chunked,
我这个小demo实现的是根据Content-Length判断read结束.
over, 未完待续...
来源:http://hi.baidu.com/teng0210/blog/item/4955e8946e992b47d0135e2a.html


C语言HTTP请求GET,因对《所谓黑客揭秘》,大家都攻击代码的要求。所以我开始了为期两周的C/C++学习。由于没有任何C/C++基础,而是临时突击,所以代码肯定漏洞甚多,请观者见谅。同时欢迎拍砖或者支出代码错误,以求大家共同进步。:



来自:http://blog.csdn.net/aofengdaxia/article/details/5984431

作者:jackxiang@向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除
地址:https://jackxiang.com/post/3696/
版权所有。转载时必须以链接形式注明作者和原始出处及本声明!


最后编辑: jackxiang 编辑于2015-2-12 14:04
评论列表
发表评论

昵称

网址

电邮

打开HTML 打开UBB 打开表情 隐藏 记住我 [登入] [注册]