MTK HTTP 协议之内核

#include "nw_define.h"
#include "nw_interface.h"
#include "Vmsys.h"
#include "Stdio.h"
#include "Soc_consts.h"
#include "String.h"
//#include "Soc_sap.h"
#include "MMI_include.h"
//#include "ProtocolEvents.h"
#include "App2soc_struct.h"

#define NW_FILE_DOWNLOAD	L"E:\\download.txt"

#define HTTP_URL_NAMELENGHt 65
nw_int8 *http_temp;
nw_uint8 nw_http_host[256] = {0};
#define NW_HTTP_REQUEST_URL	"http://wap.163.com"
const void *NW_HTTP_CMWAP_GATEWAY = "10.0.0.172";
static nw_uint16 nw_http_port = 0;
char http_buff[5000] = {0};

NW_HTTP_DATA *nw_http_data;
NW_HTTP_REQ_INFO *nw_req_info ;

#define NW_HTTP_CMWAP_PORT	(80)
#define NW_HTTP_RECEVICE_BUFFER_LENGTH	(20*1024)
#define NW_HTTP_SEND_BUFFER_LENGTH	(4*1024)

extern nw_uint16 nw_http_timer_start(nw_int8 app_index, nw_uint32 delay, NW_TIMER_CALLBACK callback_func, NW_TIMER_TYPE type);
extern nw_uint8 nw_soc_gethostbyname_callback(void* p);
extern void nw_soc_gprs_close(void);
extern void nw_http_main_timer_stop();
void nw_http_close();
void nw_http_error()
{
	
}

nw_uint16 nw_http_port_get(void)
{
	return nw_http_port;
}

//应用全部退出时处理
void nw_http_destroy_all(void)
{
	if(nw_http_data->nw_soc_id!= -1)
	{
		nw_http_close(nw_http_data->nw_soc_id);
	}
	nw_soc_gprs_close();
	nw_http_main_timer_stop();
}

void nw_http_close(nw_int32 soc_id)
{
	nw_soc_close(soc_id);
	nw_mem_free(&(void *)(nw_http_data->nw_send_buf));
	nw_mem_free(&(void *)(nw_http_data->nw_recv_buf));
	nw_http_data->nw_soc_id= -1;
	nw_fs_close(nw_http_data->file_handle);
	
	nw_http_timer_stop(nw_http_get_timer_id_by_app_index(soc_id, NW_TIMER_HTTP_TIMER_OUT));
  	nw_http_destroy_all(); //默认情况,一次http连接之后,应用全部退出一下。
}

void nw_http_parse_ip_port(char* host)
{
	char *s = NULL;
	char *host_start = NULL;
	char *host_end = NULL;
	memset(nw_http_host, 0, 256);
	nw_http_port = 80;

	//跳过"http://"
	s = strstr(host, "//");
	if (s == 0)
	{
		s = host;
	}
	else
	{
		s += 2;
	}
	host_start = s;
	s = (nw_int8*)strchr(host_start, ':');
	host_end = strchr(host_start, '/');
	if (s == 0 
		|| (host_end != 0 && s > host_end))
	{
		if (host_end != 0)
		{
			memcpy(nw_http_host, host_start, host_end - host_start);
		}
		else
		{
			memcpy(nw_http_host, host_start, strlen(host_start));
		}
		nw_http_port = 80;
	}
	else
	{
		memcpy(nw_http_host, host_start, s - host_start);
		nw_http_port = atoi(s + 1);
	}
}

nw_int8* nw_http_parse_get_str(nw_int8* url)
{
	char* s = url;
	s = strstr(url, "//");
	if (s == 0)
	{
		s = url;
	}
	else
	{
		s += 2;
	}
	return strchr(s, '/');
}

void nw_http_head_handle()
{

	nw_int8 http_name[65];
	nw_int8 *head =(nw_int8 *) nw_http_data->nw_send_buf;
	
	#ifdef WIN32
	char* get_data = NULL;
	#endif

	if(NULL == head)
	{
		return;
	}
	
	nw_http_data->nw_req_head_offset = 0;
	nw_http_data->nw_req_info.req_type = NW_HTTP_TYPE_GET;
	/* 请求方式设置 Start */
	switch(nw_http_data->nw_req_info.req_type)
	{
		case NW_HTTP_TYPE_GET:
			sprintf(head, "%s", "GET ");
			nw_http_data->nw_req_head_offset = 4;
			break;
		case NW_HTTP_TYPE_POST:
			sprintf(head, "%s", "POST ");
			nw_http_data->nw_req_head_offset = 5;
			break;
		case NW_HTTP_TYPE_HEAD:
			sprintf(head, "%s", "HEAD ");
			nw_http_data->nw_req_head_offset = 5;
			break;
		default:
			break;
	}
	/* 请求方式设置 End */
#ifndef WIN32
	if(app_stricmp(nw_http_data->nw_req_info.url, "http://", 7) == 0)
	{
		sprintf(head + nw_http_data->nw_req_head_offset, "%s", nw_http_data->nw_req_info.url);
		nw_http_data->nw_req_head_offset += strlen(nw_http_data->nw_req_info.url);
	}
	else
	{
		sprintf(head + nw_http_data->nw_req_head_offset, "http://%s", nw_http_data->nw_req_info.url);
		nw_http_data->nw_req_head_offset += (strlen(nw_http_data->nw_req_info.url) + 7);
	}
#else
	nw_http_data->nw_req_info.get_data = nw_http_parse_get_str(nw_http_data->nw_req_info.url);
	get_data = nw_http_data->nw_req_info.get_data;
	if(NULL == nw_http_data->nw_req_info.get_data)
	{
		nw_http_data->nw_req_info.get_data = "/";
	}
#endif

	if(nw_http_data->nw_req_info.get_data != NULL)
	{
		sprintf(head + nw_http_data->nw_req_head_offset, "%s", nw_http_data->nw_req_info.get_data);
		nw_http_data->nw_req_head_offset += (strlen(nw_http_data->nw_req_info.get_data));
	}

	sprintf(head + nw_http_data->nw_req_head_offset, "%s", " HTTP/1.1\r\n");
	nw_http_data->nw_req_head_offset += 11;

#ifndef WIN32
	if(nw_http_data->nw_net_type == NW_HTTP_TYPE_CMNET)
	{
		sprintf(head + nw_http_data->nw_req_head_offset, "Host: %s\r\n", NW_HTTP_CMWAP_GATEWAY);
		nw_http_data->nw_req_head_offset += (strlen((void *)NW_HTTP_CMWAP_GATEWAY) + 8);
	}
	else
	{
		nw_http_parse_ip_port(nw_http_data->nw_req_info.url);
		sprintf(head + nw_http_data->nw_req_head_offset, "Host: %s\r\n", nw_http_host);
		nw_http_data->nw_req_head_offset += (strlen((void *)nw_http_host) + 8);
	}
#else
	nw_http_parse_ip_port(nw_http_data->nw_req_info.url);
	sprintf(head + nw_http_data->nw_req_head_offset, "Host: %s:%d\r\n", nw_http_host, nw_http_port);
	nw_http_data->nw_req_head_offset += (strlen(head + nw_http_data->nw_req_head_offset));
#endif

	sprintf(head + nw_http_data->nw_req_head_offset, "%s\r\n", "Accept: */*");
	nw_http_data->nw_req_head_offset += 13;
	
	if(nw_http_data->nw_req_info.ref_url != NULL
		&& strlen(nw_http_data->nw_req_info.ref_url) > 0)
	{
		sprintf(head + nw_http_data->nw_req_head_offset, "Referer: %s\r\n", nw_http_data->nw_req_info.ref_url);
		nw_http_data->nw_req_head_offset += strlen(nw_http_data->nw_req_info.ref_url) + 11;
	}

	if(nw_http_data->nw_req_info.ua == NULL || nw_http_data->nw_req_info.ua[0] == NULL)
	{
		nw_http_data->nw_req_info.ua = nw_platform_wap_ua_get();
	}
	
	sprintf(head + nw_http_data->nw_req_head_offset, "User-Agent: %s\r\n", nw_http_data->nw_req_info.ua);
	nw_http_data->nw_req_head_offset += strlen(nw_http_data->nw_req_info.ua) + 14;

	if(nw_http_data->nw_req_info.head_param != NULL)
	{	
		sprintf(head + nw_http_data->nw_req_head_offset, "%s\r\n", nw_http_data->nw_req_info.head_param);
		nw_http_data->nw_req_head_offset += (strlen(nw_http_data->nw_req_info.head_param) + 2);
	}

	sprintf((char*)head + nw_http_data->nw_req_head_offset, "%s", "\r\n");
	nw_http_data->nw_req_head_offset += 2;
	
	if(nw_http_data->nw_req_info.post_data != NULL)
	{
		memcpy(head + nw_http_data->nw_req_head_offset, nw_http_data->nw_req_info.post_data, nw_http_data->nw_req_info.post_data_length);
		nw_http_data->nw_req_head_offset += nw_http_data->nw_req_info.post_data_length;
	}
}

void nw_http_timeout_handle(void *nw_timer_param_i, void *nw_timer_param_w)
{
	NW_TIMER_TYPE type = *((NW_TIMER_TYPE*)nw_timer_param_w);
	
	nw_http_timer_stop(nw_http_get_timer_id_by_app_index(nw_http_data->nw_soc_id, type));
	nw_http_close(nw_http_data->nw_soc_id);
}

void nw_http_event_callback(void *notify_msg);

void nw_http_send_request()
{
	signed char result = 0;
	nw_int8 resultcon;
	nw_uint32 id = 0, addr = 0, addr_len = 4;
	nw_int32 soc_id = -1;

	if((nw_req_info =(void *) nw_mem_malloc(sizeof(NW_HTTP_REQ_INFO))) == NULL)
	{
		nw_http_error();
		return;
	}
	else
	{
		nw_req_info =(NW_HTTP_REQ_INFO *) (&nw_http_data->nw_req_info);
	}
	
	soc_id = nw_soc_create();
	nw_http_data->nw_soc_id = soc_id;
	
	nw_http_timer_start(soc_id, 5 * 1000, nw_http_timeout_handle, NW_TIMER_HTTP_TIMER_OUT);
	
	if(NW_HTTP_TYPE_CMWAP == nw_http_data->nw_net_type)
	{
		nw_soc_connect(soc_id, NW_HTTP_CMWAP_GATEWAY, NW_HTTP_CMWAP_PORT);
		return;
	}
	else //NW_HTTP_TYPE_CMNET
	{
		result = soc_gethostbyname(KAL_FALSE, MOD_MMI, soc_id, nw_http_host, &addr, &addr_len, 0, nw_platform_net_account_id_get());
		if (result != SOC_SUCCESS)
		{
			if (result == SOC_WOULDBLOCK)
			{
				nw_soc_mmi_frm_set_protocol_event_handler(MSG_ID_APP_SOC_GET_HOST_BY_NAME_IND, nw_soc_gethostbyname_callback);
				return ;
			}
			else
			{
				return ;
			}
		}
	}
}

extern void EntryNewScreenHttpResult();
extern void nw_http_result();

void nw_http_init(nw_int32 is_net)
{
	if((nw_http_data =(void *) nw_mem_malloc(sizeof(NW_HTTP_DATA))) == NULL)
	{
		nw_http_error();
		return;
	}
	else
	{
		memset(nw_http_data,0,sizeof(NW_HTTP_DATA));
		if((nw_http_data->nw_send_buf =(void *) nw_mem_malloc(NW_HTTP_SEND_BUFFER_LENGTH)) == NULL)
		{
			nw_http_error();
			return;
		}

		memset(nw_http_data->nw_send_buf, 0, NW_HTTP_SEND_BUFFER_LENGTH);
		nw_http_data->nw_send_buf_size = NW_HTTP_SEND_BUFFER_LENGTH;

		if((nw_http_data->nw_recv_buf = (void *)nw_mem_malloc(NW_HTTP_RECEVICE_BUFFER_LENGTH)) == NULL)
		{
			nw_mem_free(&nw_http_data);
			nw_mem_free(&nw_http_data->nw_send_buf);
			nw_http_error();
			return;
		}

		memset(nw_http_data->nw_recv_buf, 0, NW_HTTP_RECEVICE_BUFFER_LENGTH);
		nw_http_data->nw_recv_buf_size = NW_HTTP_RECEVICE_BUFFER_LENGTH;
		nw_http_data->nw_resp_head_buf =(nw_int8 *) nw_http_data->nw_recv_buf;
		if(is_net == 1)
		{
			nw_http_data->nw_net_type = NW_HTTP_TYPE_CMWAP;
		}
		else if(is_net == 2)
		{
			nw_http_data->nw_net_type = NW_HTTP_TYPE_CMNET;	
		}

	}
}


extern void nw_http_http_get_url();
void nw_http_start(nw_int32 is_net)
{
	nw_http_init(is_net);

	nw_http_http_get_url();
		
}

void nw_http_enter_headle()
{
	nw_http_head_handle();

	nw_http_send_request();
}

void nw_http_post_url_headle(nw_int8 *http_url_name)
{
	http_temp =(nw_int8 *) nw_mem_malloc(HTTP_URL_NAMELENGHt);
	mmi_ucs2_to_asc(http_temp,http_url_name);
	nw_http_data->nw_req_info.url=http_temp;
	nw_http_enter_headle();
	nw_mem_free(&http_temp);
}

void nw_http_send(nw_int32 soc_id)
{
	
	nw_int32 nw_send_length = 0, *nw_total_send_length_p = NULL;
	static nw_uint32 nw_send_length_temp = 0;
	nw_uint8 *nw_send_buffer = NULL;

	nw_send_buffer = nw_http_data->nw_send_buf;
	if(NULL == nw_send_buffer)
	{
		return;
	}
	
	nw_total_send_length_p =(nw_int32 *) &(nw_http_data->nw_req_head_offset);
	
	while((*nw_total_send_length_p) > 0)
	{
			nw_send_length = nw_soc_send(soc_id, nw_send_buffer, (*nw_total_send_length_p));
			if(nw_send_length > 0)
			{
				*nw_total_send_length_p = (*nw_total_send_length_p) - nw_send_length;
				nw_send_length_temp = nw_send_length_temp + nw_send_length;
				
				if((*nw_total_send_length_p) > 0)
				{
					memcpy(nw_send_buffer, nw_send_buffer + nw_send_length_temp, (*nw_total_send_length_p));
				}
			}
			else
			{
				break;  //其他小于0的情况,视为网络故障。
			}
	}
	nw_send_length_temp = 0;
}

char * nw_http_show()
{
	return http_buff;
}

void nw_http_recv_data_process()
{
	//接收数据处理。
	nw_int32 file_handle = 0;
	if(nw_http_data->nw_peek_data_length >= nw_http_data->nw_resp_info.content_length)
	{
		//数据全部接收完成。
		//最后一次处理数据。
		//写文件处理数据:TBD
		if(1 == nw_fs_file_exist(NW_FILE_DOWNLOAD))
		{
			nw_http_data->file_handle = nw_fs_open(NW_FILE_DOWNLOAD, FS_CREATE|FS_READ_WRITE);
			if(0 > nw_http_data->file_handle)
			{
				//文件打开失败。
				nw_http_close(nw_http_data->nw_soc_id);
				nw_fs_close(nw_http_data->file_handle);
				return;
			}
		}
		//nw_fs_seek(nw_http_data->file_handle, nw_http_data->nw_peek_data_length, FS_FILE_BEGIN);
		nw_fs_write(nw_http_data->file_handle, (void *)nw_http_data->nw_recv_buf, nw_http_data->nw_recv_data_length);
		nw_fs_close(nw_http_data->file_handle);
		nw_http_close(nw_http_data->nw_soc_id);
	}
	else
	{
		//写文件处理数据:TBD
		if(1 == nw_fs_file_exist(NW_FILE_DOWNLOAD))
		{
			nw_http_data->file_handle = nw_fs_open(NW_FILE_DOWNLOAD, FS_READ_WRITE);
			if(0 != nw_http_data->file_handle)
			{
				//文件打开失败。
				nw_http_close(nw_http_data->nw_soc_id);
				return;
			}
		}
		nw_fs_seek(nw_http_data->file_handle, nw_http_data->nw_peek_data_length, FS_FILE_BEGIN);
		nw_fs_write(nw_http_data->file_handle, (void *)nw_http_data->nw_recv_buf, nw_http_data->nw_recv_data_length);
	  //数据写完毕。
	  memset(nw_http_data->nw_recv_buf, 0, nw_http_data->nw_recv_buf_size);
	}

	//EntryNewScreenHttpResult();
	nw_http_result();
}


void nw_http_resp_head_parse(NW_HTTP_RESP_INFO* resp_info, nw_int8* resp_buf)
{
	nw_int8* s;
	nw_int8* param_name;
	nw_int8* param_value;
	resp_info->status = atoi(resp_buf + 9);
	
	s = strstr(resp_buf, "\r\n");
	s += 2;
	while (*s != '\r')
	{
		param_name = s;
		s = strstr(s, "\r\n");
		if (s == 0)
		{
			return;
		}
		s[0] = 0;
		s += 2;
		
		param_value = strchr(param_name, ':');
		param_value[0] = 0;
		param_value += 1;
		while (param_value[0] == ' ')
		{
			param_value += 1;
		}

		if (app_stricmp(param_name, "content-type") == 0)
		{//content-type
			if (strstr(param_value, "gb2312") != 0 
				|| strstr(param_value, "GB2312") != 0 
				|| strstr(param_value, "Gb2312") != 0 
				|| strstr(param_value, "gB2312") != 0)
			{
				resp_info->charset = 1;
			}
			
			if (app_stricmp(param_value, "text/html", 9) == 0)
			{
				resp_info->content_type = NW_MIME_TEXT_HTML;
			}
			else if (app_strnicmp(param_value, "text/vnd.wap.wml", 16) == 0 
				|| app_strnicmp(param_value, "application/vnd.wap.xhtml+xml", 29) == 0)
			{
				resp_info->content_type = NW_MIME_TEXT_WML;
			}
			else if (app_strnicmp(param_value, "application/xhtml+xml", 21) == 0)
			{
				resp_info->content_type = NW_MIME_TEXT_XHTML;
			}
			else if (app_strnicmp(param_value, "application/vnd.wap.mms-message", 31) == 0)
			{
				resp_info->content_type = NW_MIME_MMS;
			}
			else if (app_strnicmp(param_value, "text/vnd.sun.j2me.app-descriptor", 32) == 0)
			{
				resp_info->content_type = NW_MIME_JAVA_JAD;
			}
			else if (app_strnicmp(param_value, "application/vnd.symbian.install", 31) == 0)
			{
				resp_info->content_type = NW_MIME_SYMBIAN_SIS;
			}
			else if (app_strnicmp(param_value, "image/jpeg", 10) == 0)
			{
				resp_info->content_type = NW_MIME_IMAGE_JPEG;
			}
			else if (app_strnicmp(param_value, "image/gif", 9) == 0)
			{
				resp_info->content_type = NW_MIME_IMAGE_GIF;
			}
			else if (app_strnicmp(param_value, "image/png", 9) == 0)
			{
				resp_info->content_type = NW_MIME_IMAGE_PNG;
			}
			else if (app_strnicmp(param_value, "application/x-gzip", 18) == 0)
			{
				resp_info->content_type = NW_MIME_EBK2_ZLIB_PAGE;
			}
		}
		else if (app_stricmp(param_name, "content-length") == 0)
		{//content-length
			resp_info->content_length = atoi(param_value);
		}
		else if (app_stricmp(param_name, "location") == 0)
		{//location
			resp_info->location = param_value;
		}
		else if (app_stricmp(param_name, "transfer-encoding") == 0)
		{//transfer-encoding
			if (app_strnicmp(param_value, "chunked", 7) == 0)
			{
				resp_info->is_chunked = 1;
			}
		}
		
	}
}

nw_int32 nw_http_get_resp_info(nw_int8* nw_data_buf, nw_uint32 nw_data_length)
{
	nw_int8 *nw_content;
	nw_int8 *nw_chunk;
	NW_HTTP_RESP_INFO *nw_resp_info = &(nw_http_data->nw_resp_info);
	nw_uint32 nw_content_length = 0;
	nw_uint32 nw_part_length = 0;
	
	nw_content = strstr(nw_data_buf, "\r\n\r\n");
	if (nw_content == 0)
	{
		return -1;
	}
	nw_content += 4;

	//头部信息保存分析
	if (nw_http_data->nw_resp_head_offset == 0)
	{
		nw_http_data->nw_resp_head_offset = nw_content - nw_data_buf;
		nw_http_resp_head_parse(nw_resp_info, nw_http_data->nw_resp_head_buf);
	}
	
	nw_resp_info->content_offset = nw_content - nw_data_buf;
	
	//chunk处理
	if (nw_resp_info->is_chunked)
	{//Transfer-Encoding: chunked
		nw_part_length = strtoul(nw_content, &nw_chunk, 16);
		if (nw_part_length == 0)
		{//没有内容
			nw_resp_info->content_length = 0;
			return 0;
		}		
		nw_content_length += nw_part_length;
		nw_content = nw_chunk + 2 + nw_part_length;
		
		while (nw_content - nw_data_buf < nw_data_length
			&& (nw_part_length = strtoul(nw_content, &nw_chunk, 16)) > 0)
		{
			nw_content_length += nw_part_length;
			nw_content = nw_chunk + 2 + nw_part_length;
		}

		nw_resp_info->content_length = nw_content_length;
		if (nw_content - nw_data_buf < nw_data_length)
		{
			nw_uint32 move_length = 0;
			nw_content = nw_data_buf + nw_resp_info->content_offset;
			move_length = nw_data_length - nw_resp_info->content_offset;
			while ((nw_part_length = strtoul(nw_content, &nw_chunk, 16)) > 0)
			{
				move_length -= (nw_chunk + 2 - nw_content);
				memmove(nw_content, nw_chunk + 2, move_length);
				nw_content += nw_part_length;
			}
			return 0;
		}
		else
		{
			return -1;
		}
	}
	return 0;
}


void nw_http_recv(nw_int32 soc_id)
{
	//TBD 收到数据后写文件,接收请求处理。
  nw_uint8 *nw_recv_buffer = NULL;
	nw_int32 nw_recv_length = 0, nw_recv_buffer_length = 0;

	nw_recv_buffer = nw_http_data->nw_recv_buf;
	if(NULL == nw_recv_buffer)
	{
		return;
	}
	nw_recv_buffer_length = nw_http_data->nw_recv_buf_size;
	//nw_recv_length = (nw_http_data[nw_http_app_index].nw_recv_data_length = 0) ;
	nw_http_data->nw_recv_data_length = 0;

	while(nw_http_data->nw_recv_data_length < nw_recv_buffer_length) //注意缓存区满,需要多次提取
	{
		nw_recv_length = nw_soc_recv(soc_id, nw_recv_buffer, (nw_recv_buffer_length - nw_http_data->nw_recv_data_length));
		if(nw_recv_length > 0)
		{
			nw_http_data->nw_recv_data_length += nw_recv_length;
			nw_http_data->nw_peek_data_length += nw_recv_length;
			if(nw_http_data->nw_resp_info.content_length == 0)
			{
				//nw_http_get_resp_info( (nw_int8 *)nw_http_data->nw_recv_buf, nw_http_data->nw_recv_data_length);
			}
		}
		else
		{
			break;//小于0的情况视为错误处理
		}
	}
	memcpy(http_buff,nw_recv_buffer, nw_http_data->nw_recv_data_length);
	nw_http_recv_data_process();
	//TBD 满的情况下,接收下。
}

void nw_http_connect(nw_int32 soc_id)
{
	nw_http_timer_stop(nw_http_get_timer_id_by_app_index(soc_id, NW_TIMER_HTTP_TIMER_OUT));
	nw_http_send(soc_id);
}

void nw_http_event_callback(void* notify_msg)
{
	app_soc_notify_ind_struct* nw_soc_notify = (app_soc_notify_ind_struct*)notify_msg;
	nw_int32 soc_id = -1;
	
	nw_int8 nw_http_app_index = -1;

	if(NULL == nw_soc_notify)
	{
		return;
	}

	soc_id = nw_soc_notify->socket_id;
	
	switch(nw_soc_notify->event_type)
	{
	case SOC_READ:
		nw_http_recv(soc_id);
		break;
				
	case SOC_WRITE:
		nw_http_send(soc_id);
		break;
				
	case SOC_CONNECT:
		nw_http_connect(soc_id);
		break;
				
	case SOC_CLOSE:
		nw_http_close(soc_id);
		break;
				
	default:
		break;
	}
}
 
还有很多问题,因为有别的事情处理,所以没有继续优化,给个参考

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值