您的位置:首页 > 理论基础 > 计算机网络

如何利用socket进行HTTP访问

2011-05-20 18:27 726 查看
平常我们要访问某个URL一般都是通过浏览器进行:提交一个URL请求后,浏览器将请求发向目标服务器或者代理服务器,目标服务器或者代理服务器返回我们所需要的数据,浏览器接收到这些数据后保存成文件并进行显示。

下面我们看看如何自己利用winsock2.h中的接口来实现这个功能?为了简化问题,作以下假设:

通过代理服务器进行HTTP访问,这样就省去了对URL进行DNS解析的步骤,假设代理服务器的地址为:192.168.0.1:808。

这个功能由以下几个部分组成:

1.如何建立连接?

2.如何发送请求?

3.如何接收数据?

4.如何判断数据接收完成?

下面我们依次来看下这些问题如何解决

一、如何建立与服务器之间的连接

HTTP基本TCP,所以我们需要与服务器建立连接,然后才能发送数据。

建立连接参考如下函数socket_open:

01

/*

02

*打开Socket,返回socketId,-1表示失败

03

*/

04

int

socket_open(

int

IP,

int

Port,

int

type){

05

SOCKETsocketId;

06


struct

sockaddr_inserv_addr;

07


int

status;

08


09


socketId=socket(AF_INET,SOCK_STREAM,0);

10


11


if

((

int

)socketId<0)

12


{

13


printf

(

"[ERROR]Createasocketfailed!/n"

);

14


return

-1;

15


}

16


17


memset

(&serv_addr,0,

sizeof

(serv_addr));

18


serv_addr.sin_family=AF_INET;

19


serv_addr.sin_addr.s_addr=ntohl(IP);

20


serv_addr.sin_port=htons((

USHORT

)Port);

21


status=connect(socketId,(

struct

sockaddr*)&serv_addr,

sizeof

(serv_addr));

22


if

(status!=0)

23


{

24


printf

(

"[ERROR]Connectingfailed!/n"

);

25


closesocket(socketId);

26


return

-1;

27


}

28


return

socketId;

29

}

调用方式如下


1

int

socketId=socket_open(0xC0A80001,808,0);

//0xC0A80001是192.168.0.1的十六进制写法。

二、如何发送请求

发送数据要根据HTTP协议的要求附加协议头:

1

static

const

char

*protocolHead=

"GEThttp://www.xxx.com/index.html
HTTP/1.1/n"

2


"Accept:
image/gif,image/x-xbitmap,image/jpeg,image/pjpeg,
application/x-shockwave-flash,application/vnd.ms-excel,
application/vnd.ms-powerpoint,application/msword,*/*/n"

3


"Accept-Language:zh-cn/n"

4


"User-Agent:iPanelBrowser/2.0/n"

5


"Host:www.xxx.com:80/n"

6


"Connection:close/n/n"

这里使用GET来获取指定URL的指定文档。

建立连接后使用send将这些数据发送出去:

send(socketId,protocolHead,strlen(protocolHead),0);

发送完成HTTP请求后就等待接收数据。

三、如何接收数据

这里采用select循环查询的方式来判断有无数据到来:

01

struct

timeval

tm

={0,7};

02


fd_setfds_r;

03


int

status;

04


char

recvBuf[4096]={‘/0’};

05


FD_ZERO(&fds_r);

06


FD_SET(socketId,&fds_r);

07


08

status=select(socketId+1,&fds_r,0,0,&

tm

);

//socketId在这里是最大的fd

09


10


if

(status>0&&FD_ISSET(socketId,&fds_r))

11

{

12


printf

(

"Socketisreadable...fd=[%d]/n"

,socketId);

13


recv(socketId,recvBuf,4096,0);

14

}

这样数据包就保存到缓冲区中了。

四、如何判断数据接收完成

首先对返回数据的状态进行判断,仅当状态为“HTTP200OK”时才表明正确返回,这时才对数据进行解析并保存,如果状态为HTTP404NOTFOUND或者其它状态则表明没有找到资源或者出现其它问题,可参考HTTP1.1状态代码及其含义。


数据正确返回时,为了将实际数据从协议中分离出来进行保存,需要对HTTP数据包进行解析得到Content-Length,然后在包含Content-
Length的当前数据包或者随后的数据包中查找第一个空行,这就是内容(Content)的开始位置,再配合前面解析得到的Content-
Length,就能够知道什么时候数据接收完成了。换行符为“/r/n”,也兼容“/n”或者“/r”,设换行符为^P,则空行如果位于内容中间或结尾则
可查找“^P^P”,若位于开头,则查找^P。

基本就是上面这些,这四个问题解决了,那么整个问题也就解决了!

摘自http://dev.firnow.com/course/3_program/c++/cppsl/2008227/101925.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: