linux 模拟socket请求,SOCKET模拟HTTP请求

SOCKET模拟HTTP请求

HTTP请求头部样例:

GET HTTP/1.1

Accept: html/text

Host: 220.181.6.175:80

Connection: Close

这是一个请求百度页面的头部。

属性和值的命名中间用:和空格隔开,结尾使用\r\n,头部结束使用\r\n\r\n

GET表示采用GET方法,当然我们常见的还有POST等其他方法,具体每个方法的意义可以查看RFC文档(附件)。

请求URL的绝对地址,如果使用相对地址可以改为/或者/index.html.注:后面的/不能少。

HTTP/1.1版本号

Accept接受响应的类型

Host请求的主机地址和端口

Connection:如果值为close则告诉服务器,当本次数据传递完毕以后,就会断开TCP链接。如果值为Keep-Alive则告诉服务器,数据传输结束后,本次链接不断开,等待后续请求。

用SOCKET模拟递交HTTP请求步骤:

1.首先建立和HTTP服务器的TCP链接

2.组织HTTP请求

3.发送请求

4.获取响应

一个下载百度首页的例子:

#include "stdlib.h"

#include "sys/types.h"

#include "sys/socket.h"

#include "netinet/in.h"

#include "netdb.h"

#include "string.h"

#include "arpa/inet.h"

#include "ctype.h"

#include "stdio.h"

#include "sys/stat.h"

#include "fcntl.h"

void send_and_recv(int sockfd, char * url, char * fun_type, char * accept_type,

char * ip, int port, char * file_loc, char * body, char * connection_type);

//sockfd表示TCP链接的套接字,url请求服务的相对或者绝对地址,fun_type请求方法,accept_type接受类 型,ip,port请求的服务器的地址和端口,file_loc下载文件存放位置,body请求的主体,connection_type用来指定connection的类型int main() {

int sockfd;

struct sockaddr_in serv_socket;

int port = 80;

char ip[] =

"220.181.6.175"; //ip地址,可以通过gethostbyname来获取char file_loc[] =

"/programe/http/temp.html"; //下载的存放位置bzero(&serv_socket,

sizeof(struct sockaddr_in));

serv_socket.sin_family = AF_INET;

serv_socket.sin_port = htons(port);

inet_pton(AF_INET, ip,

&serv_socket.sin_addr);

sockfd = socket(AF_INET, SOCK_STREAM,

0);

int flag = connect(sockfd, (struct

sockaddr *)&serv_socket, sizeof(serv_socket)); //建立和HTTP服务器的TCP链接if(flag < 0) {

printf("connect error!!! flag = %d\n", flag);

exit(1);

}

send_and_recv(sockfd,

"", "GET", "html/text", ip,

port, file_loc, NULL, "Close"); //下载的主体函数close(sockfd);

exit(0);

}

void send_and_recv(int sockfd, char * url, char * fun_type, char * accept_type,

char * ip, int port, char * file_loc, char * body, char * connection_type) {

char * request = (char *) malloc (4

* 1024 * sizeof(char));

if(body)

sprintf(request, "%s %s HTTP/1.1\r\nAccept: %s\r\nHost:

%s:%d\r\nConnection: %s\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-L

ength: %d\r\n\r\n%s", fun_type, url, accept_type, ip, port,

connection_type, body, strlen(body));

else

sprintf(request, "%s %s HTTP/1.1\r\nAccept: %s\r\nHost:

%s:%d\r\nConnection: %s\r\n\r\n", fun_type, url, accept_type, ip, port,

connection_type

);

//以上是在组织请求的头部,打印出的结果就是文章开头所写int send = write(sockfd, request,

strlen(request));

printf("%s", request);

free(request);

char * response = (char *) malloc

(1024 * sizeof(char));

if(file_loc) {

int file = open(file_loc, O_RDWR | O_APPEND);

int length;

do {

length = read(sockfd, response, 1024);

char * loc = strstr(response, "\r\n\r\n"); //截获返回头部,以\r\n\r\n为标识if(loc) {

int loci = loc - response + 4;

write(1, response, loci);//如果是响应头部就打印至屏幕write(file, loc, length - loci);//如果是响应主体就写入文件} else {

write(file, response, length);

}

if(!length)//注意,因为之前采用的是close方法,也就是说一旦传输数据完毕,则服务器端会断开链接,则read函数会返回0,所以这里 会退出循环。如果采用的是Keep-Alive则服务器不关闭TCP链接,也就说程序将会被阻塞在read函数中,因此要注意的是自己判断是否读到了响应 的结尾,然后在再次调用read之前退出循环。break;

} while(1);

close(file);

} else {

int length;

do {

length = read(sockfd, response, 1024);

printf("%s", response);

if(!length)

break;

} while(1);

}

free(response);

}

之前的头部比较简单,在发送请求的时候,我们常常会递交表单,如果采用GET方法,则可以通过URL传递参数。如果采用POST,则新的HTTP请求看上去应该是这样。(带COOKIE)

POST http://192.168.1.154:8888/httpstudy2/servlet/IndexServlet HTTP/1.1

Accept: html/text

Host: 192.168.1.154:8888

Cookie: username=difa; password=yuna

Connection: Close

Content-Type: application/x-www-form-urlencoded

Content-Length: 29

username=hello&password=world

Content-Type表示主体类型

Content-Length表示主体长度,不包括头部。

整个发送的HTTP请求应该是:

POST http://192.168.1.154:8888/httpstudy2/servlet/IndexServlet

HTTP/1.1\r\nAccept: html/text\r\nHost: 192.168.1.154:8888\r\nCookie:

username=difa; password=yuna\r\nConnection: Close\r\nContent-Type:

application/x-www-form-urlencoded\r\nContent-Length:

29\r\n\r\nusername=hello&password=world

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值