socket編寫一個簡單的http請求
本文介紹如何使用socket編程,直接向服務器發送獲取文件的請求。
需要環境:ubuntu系統+windows安裝hfs服務器
http是應用層協議,傳輸層是基於tcp協議的,因此只需使用socket編寫一個基於tcp的client即可。
http請求流程,簡單來說就是,設備向服務器發送一個請求(post or get),設備緊接着就收到服務器的響應。
區別的地方:
請求
http get:直接請求一次,只需要socket send發送一次數據即可。----請求頭
http post: 除了發送請求頭之外還要發送post 數據,所以需要發送兩次。
響應
需要分兩次接收數據,一次是響應頭數據,第二次返回的數據。
代碼實現如下:
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
#include<sys/types.h>
#include<signal.h>
#include<stdlib.h>
#define DBG(...) printf("[%s,%d]",__FUNCTION__,__LINE__);printf(__VA_ARGS__)
#define HOST_SER "192.168.21.1"
#define PORT_SER 80
#define PORT_SER_FILE "/HFSSERVER/datatest.txt"
int main(int argc, const char *argv[])
{
int sockfd;
char databuf[512];
char recvbuf[512];
memset(databuf,0,512);
memset(recvbuf,0,512);
//創建套接字
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd == -1)
{
DBG("socket\n");
return -1;
}
//填充地址結構
struct sockaddr_in seraddr,cliaddr;
memset(&seraddr,0,sizeof(seraddr));
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(PORT_SER);
seraddr.sin_addr.s_addr = inet_addr(HOST_SER);
//連接服務器請求
if(connect(sockfd,(struct sockaddr*)&seraddr,sizeof(seraddr)) == -1)
{
DBG("connect fail\n");
return -1;
}
else
{
//http請求頭
sprintf(databuf,"GET %s HTTP/1.1\r\nHost:%s\r\n\r\n",PORT_SER_FILE,HOST_SER);
DBG("req str:%s\n",databuf);
//發送http請求
send(sockfd,databuf,strlen(databuf),0);
//接收響應頭
recv(sockfd,recvbuf,sizeof(recvbuf),0);
DBG("recv buf:\n%s\n",recvbuf);
memset(recvbuf,0,512);
//接收響應數據
recv(sockfd,recvbuf,sizeof(recvbuf),0);
DBG("recv buf:\n%s\n",recvbuf);
}
return 0;
}
編譯完成,因爲此時ubuntu系統,我們還需要在windows下搭建hfs服務器(作爲一個文件服務器,前面博客有過介紹)。
#define HOST_SER “192.168.21.1” //服務器地址
#define PORT_SER 80 //http端口
#define PORT_SER_FILE “/HFSSERVER/datatest.txt” //服務器文件
筆者windows服務爲下圖目錄,文件內容如下:
編譯運行
真正的httpclient源碼中http接口的實現肯定比較複雜,對於請求,需要請求內容的拼接就變得複雜的,請求的其他項都可能被使用,同樣,對於響應數據的響應頭也需要做解析,所以其接口會被層層封裝。最終原理就是向服務器+80端口建立連接後,進行數據傳輸。