http客户端如何写

使用wireshark协助,设置网卡本地,设置过滤器:http && (ip.src == 192.168.1.80 && ip.dst == 192.168.1.81) || (ip.src == 192.168.1.81 && ip.dst == 192.168.1.80)。

查看数据:

接收数据:
Content-Length:17364652代表所发的数据字节总数,在 后即是数据的开始处。
数据为:LOAD为文件的魔术字 表示文件的一个唯一值,可以将分割的块聚在一起。

时间

有限搬代码:

int Get_File(int sockfd,char *url,int filelength,char *filebuf)
{
	int count;
	char range[32];
	int i;
	int ret = 0;
	char *p = NULL;
	int downOver=0;
	int downlength=0,writeRet;
	int p_file;
	int s32TimeOut=5*1000;
	fd_set rfds;
	int nRecvBuf=64*1024;//设置为32K
	struct timeval tv;
	
	count  = (filelength%MAX_RECV_SIZE)?(filelength/MAX_RECV_SIZE +1):(filelength/MAX_RECV_SIZE);

	for(i=0;i<1;i++)
	{
		if((i == (count-1))&&(filelength%MAX_RECV_SIZE))
			sprintf(range,"%d-%d",i*MAX_RECV_SIZE,filelength-1);
		else
			sprintf(range,"%d-%d",i*MAX_RECV_SIZE,(i+1)*MAX_RECV_SIZE-1);

		Package_Url_Get_File(url,range);
		printf("send = %s 
",g_buf_send);

		Send(sockfd, g_buf_send, strlen(g_buf_send), 0);
		Net_Http_GetResponseHeader(sockfd);
		/*需改为提取http 返回协议头和协议体总长,然后定长接收*/
		//setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,(char*)s32TimeOut,sizeof(s32TimeOut));
		//setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,(char*)nRecvBuf,sizeof(nRecvBuf));
		while(!downOver)
		{
re_recv:
		      tv.tv_sec  = 5;
         	      tv.tv_usec = 0;
	             FD_ZERO(&rfds);     //每次循环都要清空集合,否则不能检测描述符变化
                    FD_SET(sockfd, &rfds);     //添加描述符
			memset(g_buf_recv,0x0,sizeof(g_buf_recv));		
			switch (select(sockfd + 1, &rfds, NULL, NULL, &tv))
          	      {
                		case 1:
					{
						usleep(100);
						ret = Recv(sockfd,g_buf_recv,sizeof(g_buf_recv)-1,0);
						s32TimeOut = 0;
						printf("recv len = %d
", ret);
						 if ( 0 > ret )
                 				   {
                  				           printf("recvfrom error
");
                    				    break;
                 				   }
						 p=g_buf_recv;
						 Write_File(p,"",ret);
						 printf("strlen(p)=%d 
",strlen(p));
						 if(ret > 0) downlength += ret;
					        if(downlength >= filelength) downOver = 1;
						 goto re_recv;
						 
                			}
				case 0:
					{
						printf("timeout
");//再次轮询

              			        s32TimeOut--;
              			        if (s32TimeOut == 0)
               			    	  {
                 				       printf("last timeout
");
                  				  }
                  				  break;
					}
				default:
                 		   printf("Failed to select
");//select错误,退出程序
			}

		}
	}
	return 0;
}
void Package_Url_Get_File(char *url, char *range)
{
	char buf_range[64];
	memset(g_buf_send,0x0,sizeof(g_buf_send));		                                          
	sprintf(g_buf_send, "GET %s",url);

	
	//HTTP/1.1
 前面需要一个空格
	strcat(g_buf_send," HTTP/1.1
");
	strcat(g_buf_send, "Host: ");
	strcat(g_buf_send, IP);
	strcat(g_buf_send, ":");
	strcat(g_buf_send, PORT);
	
//	sprintf(buf_range, "
Range: bytes=%s
",range);
//	strcat(g_buf_send,buf_range);
	strcat(g_buf_send,"
Connection: Keep-Alive

");
	

}

  

int Send(int sockfd, char *sendbuf, int len, int flags)
{
	int sendlen = 0;
	int ret = -1;

	while(sendlen < len)
	{
		ret = send(sockfd, sendbuf+sendlen, len-sendlen, flags); 
		if(-1 == ret)
		{
			perror("send");
			exit(EXIT_FAILURE);
		}
		else
			sendlen += ret;

	}

	return 0;

}

  

int Recv(int  sockfd,  char *recvbuf, int  len,  int  flags)
{
	int recv_len;

	if ((recv_len = recv(sockfd, recvbuf, len, flags)) < 0)
	{
		perror("recv error");
		exit(EXIT_FAILURE);
	}

	return recv_len;
}

  

char* Net_Http_GetResponseHeader(int sockfd)
{
	char c = 0;
	int nIndex = 0;
	static char ResponseHeader[1024]={0};
	int bEndResponse = 0;
	while(!bEndResponse && nIndex < 1024)
	{
		recv(sockfd,&c,1,0);
		ResponseHeader[nIndex++] = c;
		if(nIndex >= 4)
		{
			if(ResponseHeader[0]!='H'&&ResponseHeader[1]!='T'
				&&ResponseHeader[2]!='T'&&ResponseHeader[3]!='P')
			{
				printf("ResponseHeader error !
");
				return NULL;
			}
			if(ResponseHeader[nIndex - 4] == '
' && ResponseHeader[nIndex - 3] == '
'
				&& ResponseHeader[nIndex - 2] == '
' && ResponseHeader[nIndex - 1] == '
')
			bEndResponse = 1;
		}
	}
	ResponseHeader[nIndex]=0;
	printf("ResponseHeader:%s 
",ResponseHeader);
	return ResponseHeader;
	
}

  

 假如要实现断点则只需要加入字段Range: bytes=%d-  (%d)是你需要开始下载的文件的起始字节数。

1.在linux 在写代码过程中要注意写入文件时候,写入的字节数要是recv函数返回的值为准,不要使用strlen函数,在返回的包中,尽量先将包头过滤出来。

2.在window下,打开文件函数fopen需要指定wb二进制方式打开,否则在windows下,fwrite函数写入数据时会加上回车符OX0D。

3.在window下,调试时候,如果在调用fwrite函数写入,没有经过fclose,ctrl+c程序终止的话会造成最后一段数据没有真正写入到文件。

原文地址:https://www.cnblogs.com/kernel-style/p/3336550.html