1. 程式人生 > >從硬體底層通訊看http協議和https協議的資料流

從硬體底層通訊看http協議和https協議的資料流

     嵌入式硬體與伺服器的通訊常常採用http協議或是https協議,實際上https協議就是http協議+SSL加密通訊,簡單點說就是把http協議的資料經過一定的演算法加密後傳送出去,接收方收到後再解密出來。http協議是執行在tcp協議的上一層,也就是說協議資料是在TCP資料的流的基礎上再進行編碼獲得。接觸過乙太網底層程式設計的同學都熟悉socket程式設計,那麼一段資料按http協議進行編碼,呼叫write()函式寫入網路socket上,對方收到的資料就是http資料。

      http協議是一種無連線,無狀態的連線協議,無連線的意思是說,需要通訊時才建議連線(TCP連線),通訊完成後一般關閉連結。無狀態協議的話就是一次性,只有一個狀態,不像TCP協議一樣,通訊過程中有各種狀態之間依次變換才能完成通訊。協議對話的發起由客戶端發出請求給伺服器,伺服器根據客戶端發來的資料進行響應。

客戶端請求訊息

客戶端傳送一個HTTP請求到伺服器的請求訊息包括以下格式:請求行(request line)、請求頭部(header)、空行和請求資料四個部分組成,下圖給出了請求報文的一般格式。

2012072810301161


伺服器響應訊息

     HTTP響應由四部分組成,分別是狀態行、訊息報頭,空行和響應正文。


      http協議佔用TCP通訊的80埠號,https協議通訊佔用TCP通訊的443埠號。上面只是介紹了協議,可能你還是不太明白網路上的資料流是什麼樣子的。一個示例如下:

/*請百度伺服器*/
#define SIMPLE_GET_REQUEST \
    "GET / HTTP/1.1\r\n" \
    "Host: www.baidu.com\r\n" \
    "Connection: close\r\n" \
    "\r\n"
/*簡單的HTTP請求*/
void simple_http_get( char* host, char* query )
{
    OSStatus err;
    int client_fd = -1;
    fd_set readfds;
    char ipstr[16];
    struct sockaddr_in addr;
    HTTPHeader_t *httpHeader = NULL;
    http_context_t context = { NULL, 0 };
    struct hostent* hostent_content = NULL;
    char rcv_buf[1024];
    char **pptr = NULL;
    struct in_addr in_addr;

    hostent_content = gethostbyname( host );
    require_action_quiet( hostent_content != NULL, exit, err = kNotFoundErr);
    pptr=hostent_content->h_addr_list;
    in_addr.s_addr = *(uint32_t *)(*pptr);
    strcpy( ipstr, inet_ntoa(in_addr));
    http_client_log("HTTP server address: %s, host ip: %s", host, ipstr);

    /*HTTPHeaderCreateWithCallback set some callback functions */
    httpHeader = HTTPHeaderCreateWithCallback( 1024, onReceivedData, onClearData, &context );
    require_action( httpHeader, exit, err = kNoMemoryErr );

    client_fd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
    addr.sin_family = AF_INET;
    addr.sin_addr = in_addr;
    addr.sin_port = htons(80);
    err = connect( client_fd, (struct sockaddr *)&addr, sizeof(addr) );
    require_noerr_string( err, exit, "connect http server failed" );

    /* Send HTTP Request */
    send( client_fd, query, strlen( query ), 0 );

    FD_ZERO( &readfds );
    FD_SET( client_fd, &readfds );

    select( client_fd + 1, &readfds, NULL, NULL, NULL );
    if ( FD_ISSET( client_fd, &readfds ) )
    {
    n= read(client_fd, rcv_buf, sizeof(rcv_buf))
   }
}


void main(void)
{
    simple_http_get("www.baidu.com", SIMPLE_GET_REQUEST);
}

      通過上面的示例就不難看出,http請求百度伺服器就是發出一個GET請求了,請求的編碼就是按照協議寫一些字串以換行結尾,之後把這些編碼好的字串通過write()函式寫入到百度伺服器的80埠上就可以了。

"GET / HTTP/1.1\r\n" \
    "Host: www.baidu.com\r\n" \
    "Connection: close\r\n" \
    "\r\n"