嵌入式硬件与服务器的通信常常采用http协议或是https协议,实际上https协议就是http协议+SSL加密通信,简单点说就是把http协议的数据经过一定的算法加密后发送出去,接收方收到后再解密出来。http协议是运行在tcp协议的上一层,也就是说协议数据是在TCP数据的流的基础上再进行编码获得。接触过以太网底层编程的同学都熟悉socket编程,那么一段数据按http协议进行编码,调用write()函数写入网络socket上,对方收到的数据就是http数据。
http协议是一种无连接,无状态的连接协议,无连接的意思是说,需要通信时才建议连接(TCP连接),通信完成后一般关闭链接。无状态协议的话就是一次性,只有一个状态,不像TCP协议一样,通信过程中有各种状态之间依次变换才能完成通信。协议对话的发起由客户端发出请求给服务器,服务器根据客户端发来的数据进行响应。
客户端发送一个HTTP请求到服务器的请求消息包括以下格式:请求行(request line)、请求头部(header)、空行和请求数据四个部分组成,下图给出了请求报文的一般格式。
服务器响应消息
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"