
HTTP协议是最被广泛使用的网络传输协议所有www文件都必须遵守这个标准并且HTTP基于TCP/IP通信协议来传递数据本文的主要内容是介绍HTTP请求的的格式并且使用C语言以TCP的方式来实现请求的发送。创建套接字HTTP协议是应用层的协议而其传输接口层的实现需要通过创建套接字。inthttp_create_socket(char*ip){intsockfdsocket(AF_INET,SOCK_STREAM,0);structsockaddr_insin{0};sin.sin_familyAF_INET;sin.sin_porthtons(80);//http协议默认是80端口sin.sin_addr.s_addrinet_addr(ip);//将char*转化为无符号intif(0!connect(sockfd,(structsockaddr*)sin,sizeof(structsockaddr_in))){return-1;}fcntl(sockfd,F_SETFL,O_NONBLOCK);//设置为非阻塞returnsockfd;}关键技术阐述上述代码的第3行调用socket函数用以创建套接字描述符其中第一个参数指定使用IPv4 第二个参数SOCK_STREAM指定后默认使用TCP而不是UDP协议进行传输第三个参数一般是具体协议选择设置为0让系统自行决定即可。512行为相对固定的编程套路填充好套接字地址sockaddr_in这个结构体的相关内容与本文相关唯一值得注意的点是HTTP默认使用80端口。第14行使用fcntlfile control函数将连接设置为非阻塞。如果socket是阻塞的read的时候整个程序挂起等待io数据到来反之则不会。使用到的时候查询下这个函数的参数如何设置即可不需要特别记忆。HTTP请求报文的一般格式发送http请求的函数实现如下char*http_send_request(constchar*hostname,constchar*resource){char*iphost_to_ip(hostname);intsockfdhttp_create_socket(ip);charbuffer[BUFFER_SIZE]{0};sprintf(buffer,GET %s %s\r\n\ Host: %s\r\n\ %s\r\n\ \r\n,resource,HTTP_VERSION,hostname,CONNECTION_TYPE);send(sockfd,buffer,strlen(buffer),0);//select负责检测网络io里面有没有可读的数据fd_set fdread;FD_ZERO(fdread);//描述符集置空FD_SET(sockfd,fdread);structtimevaltv;tv.tv_sec5;tv.tv_usec0;char*resultmalloc(sizeof(int));memset(result,0,sizeof(int));while(1){//用法select(maxfd1, rset, wset, eset, NULL);intselectionselect(sockfd1,fdread,NULL,NULL,tv);if(!selection||!FD_ISSET((sockfd),fdread)){break;}else{memset(buffer,0,BUFFER_SIZE);intlenrecv(sockfd,buffer,BUFFER_SIZE,0);if(len0){break;}resultrealloc(result,(strlen(result)len1));strncat(result,buffer,len);}}returnresult;}关键技术阐述第615行像TCP这种协议数据的传输是一串一串的发送和到来的更准确的描述是数据流所以为了应对数据流断断续续到达的情况需要使用到缓冲区buffer。而http请求内容符合我们上面那张图的格式即可。这里我们为了可读性和可维护性使用了两个define#define HTTP_VERSION HTTP/1.1 #define CONNECTION_TYPE Connection: close\r\n1922行之前讲过本文中采用的是非阻塞的实现read的时候不会挂起系统继续其他的工作所以我们可以搭配使用select函数用于监听socket描述符实现事件驱动避免了忙轮询占用大量系统资源。有关细节可以看我的另一篇文章CSAPP网络编程章节实验Proxylab第2426行设置了一个超时的时间为5s超过这个时间断开连接。避免无意义的等待。第3141行用while1循环反复读取服务器响应的内容直到len等于0读取完毕打破循环退出。