MTK 上的socket
2010年10月01日
移动互联网也炒了好几年了,现在开发手机也好,单独做应用也好,都会涉及到网络这一块。MTK 提供了网络功能,在GPRS上封装了socket 功能。MTK 上的socket 其实与linux 上的有些相似,其实说到socket 编程,只要封装实现了socket,那么基本上就要实现socket那些接口。
先来简单的介绍一下socket,socket 编程是介于 传输层和 应用层之间,可以简单的理解为socket 就是封装了传输层的TCP 和 UDP 协议,使用户不用去封装一个 TCP 或者 UDP 包,开发使用网络通讯就更加简单了。如果拿一个寄信的过程来比喻一个网络通信过程。socket 就像给你准备好了信纸和信封,只要把你想写的内容写到信纸上,然后信封上写上地址,就可以邮寄了。信封里的内容就像 应用层协议,具体怎么写由应用之间来确定,比如说,用英文写(http 协议),懂英文的能看懂(http 服务器或者客户端能识别)。
有时候老有人问,用MTK 怎么去请求一个网页,MTK已经准备好了socket(信纸),就看要写什么样的语言能让收信方看懂。请求网页就是一个http 请求,也就是(socket)信纸上写上http请求,服务器就能返回相应答复。具体说http 请求怎么写,那就要去研究http 协议,就像要想和美国人通信,要学习英文一样
手机通信,还有一个需要提到的是APN (Access Point Name)接入点,只用设置正确的APN,才能上网。一开始没有弄明白MTK 的APN,搞出很多问题,在北京做好的DEMO,把手机拿到深圳去,就发现不能用GRPS,网络连接一直失败,尝试了N多种方法,换SIM卡,换本地手机等等,(扯远了)。以中国移动为例,介入方式有两种cmwap,cmnet。cmwap访问的是内网,ip地址是10开头,可以理解为所有的手机都是在一个大的局域网里,要访问wap 网站,需要通过wap 网关,移动的好像是(10.0.0.172:80),也就是说,所有的wap网站访问,都要通过这个代理。cmnet 就是全网模式,也就是设置了cmnet,就像接入了互联网,直接可以访问互联网。对于中国电信,不是很了解,原来去听brew 开发讲座的时候,应约记得电信只有一种内往模式。要访问外部服务器,就得去电信开通业务。如果是开发阶段,可以暂时把手机设置成card-card模式,这样就相当于移动的cmnet了。
今天主要讲一下MTK socket 基本接口。MTK socket 主要是基于 Berkeley sockets,用起来也就大同下异。MTK socket 主要有三种模式:block(阻塞),non-block(非阻塞),Asynchronous(异步),组合方式 也只有三种 1 block ,2 non-block,3 non-block + Asynchronous。
block模式下,调用相应的函数(接受或者发送数据),如果这个函数动作没有完成(没有发送或者接受完成),那么函数就不会反回,那么调用的整个task,就会阻塞,进行不了任何动作。如果在MMI MOD 里面直接用这个,那是很危险的,会出现手机没有响应这种假死现象,所以几乎不用这个模式。
non-block 模式下,调用相应的函数,可能返回ok或者block,大部分情况下返回block,表示数据还没有处理完毕,但是函数会立即返回。但是什么时候表示数据处理完成呢,这也是一个比较头疼的事情。这个时候要配合select函数来一起使用,这样就需要自己轮询去查询相应的socket是否可以使用了。一般也不用,效率比较低。
non-block + Asynchronous模式:这个模式推荐使用,可以编成工作中几乎就用这种方式,non-block,就不会阻塞,不会让应用看起来假死,Asynchronous模式,那么当使用函数返回block时,app 只要注册相应的回调函数,当数据处理完毕了,就会收到相应的通知,不用自己去轮询,效率也就高了。
MTK socket 接口声明都在头文件 soc_api.h,接口名字都以soc_ 开头。
1 soc_create 创建一个socket
/*
* 创建一个socket
* domain: 协议,现在只支持 SOC_PF_INET
* type : 该domain 下的类型,现在有 SOC_SOCK_STREAM(TCP),SOC_SOCK_DGRAM(UDP),SOC_SOCK_ SMS,SOC_SOCK_RAW
* protocol: 协议类型,除了type 为 SOC_SOCK_RAW,其他都为 0
* mod_id: 当前模块ID,主要用于接受消息
* nwk_account_id:apn 接入点
*/
kal_int8 soc_create(kal_uint8 domain,
socket_type_enum type,
kal_uint8 protocol,
module_type mod_id,
kal_uint32 nwk_account_id);
就说了一个函数,有没时间了。。。
在 MTK socket 小结 2 说了一个socket create 函数,不知道今天能说几个,create 了一个socket,就像打开了一个文件,可以对其进行操作,当然操作前要稍微进行一些设置。
//关闭socket 与 soc_create 成对使用
kal_int8 soc_close(kal_int8 s)
// 绑定一个socket 到 一个指定的ip地址和 端口。主要用于服务器短开发
// 一般ip 地址全 0,端口就是想要绑定的端口
// 在实际开发中,几乎不会用到,除非想用手机做服务器,hoho。
kal_int8 soc_bind(kal_int8 s, sockaddr_struct *addr);
// 绑定完socket 之后,就可以监听这个 ip的端口
// 这个也几乎不会用,也是用于服务器端。
// backlog 同时能连接的socket 个数
kal_int8 soc_listen(kal_int8 s, kal_uint8 backlog);
// 当有socket 连接到该机时,accept 就可以获得该连接,同样也是用于服务器端
// addr 可以获得连接过来的socket 地址
// 返回一个新的socket
kal_int8 soc_accept(kal_int8 s, sockaddr_struct *addr);
// 连接到一个指定ip地址的服务器
// 这个函数很常用,要想联网,就的通过 addr 指定ip地址和端口
// 根据不同的模式 (block, none block,asynchronous,这个函数会稍微不同
// 如果是block,那么整个task 就被block,直到connect 成功或者失败或者超时
// 这个如果在MMI task 里面,后果就会比较严重(界面不动,无响应)
// 所以最常用 none block + asynchronous, 几乎马上返回,成功或失败或者SOC_WOULDBLOCK
// 大部情况下返回SOC_WOULDBLOCK,那么就等待消息,由消息得知到底成功or失败。
// addr 就是要连接的ip地址和端口
kal_int8 soc_connect(kal_int8 s, sockaddr_struct *addr)
// 向指定的ip地址和端口发送数据
// buf 和 len 分别是要发送的内容和长度
// flag 暂时没有使用 设置为 0
// addr 指定要发送到的ip地址和端口
// 说明:如果create socket 的时候是TCP,那么还是需要先connect 到 服务器,再调用该函数
// 这与 berkeley 的 socket 规范有点区别
kal_int32 soc_sendto(kal_int8 s,
void *buf,
kal_int32 len,
kal_uint8 flags,
sockaddr_struct *addr);
// 向已经connect 的上的服务器发送数据
// buf 和 len,是要发送的内容和长度
// flags 暂时不使用
// 这个也是很常用的, 连接完毕之后,就可以发送数据了
// 比如要请求一个网页,那么就发送一个HTTP 请求就可以了
// 跟soc_connect 一样,最找在 模式 3 下使用
kal_int32 soc_send(kal_int8 s,
void *buf,
kal_int32 len,
kal_uint8 flags);
// 从指定地址接收数据
// buf 读取数据的buf,len 读取数据buf的最大长度
// flags 暂时无用,设置为0
// 返回实际读取的数据长度
kal_int32 soc_recvfrom(kal_int8 s,
void *buf,
kal_int32 len,
kal_uint8 flags,
sockaddr_struct *fromaddr);
// 从已经连接上的服务器上接收数据
// 同样最好在模式 3 下使用,当收到消息有可读数据时,
// 可以调用该函数,从socket 里面读取数据
// 参数同上
kal_int32 soc_recv(kal_int8 s,
void *buf,
kal_int32 len,
kal_uint8 flags);
// 设置socket的参数,当创建好socket 之后,就可以设置了
// 模式 3 none block + asynchronous 就是通过这个函数设置定的
kal_int8 soc_setsockopt(kal_int8 s,
kal_uint32 option,
void *val,
kal_uint8 val_size);
// 比如
S8 val = 0, ret = 0;
val = KAL_TRUE;
// 设置为none block 模式,默认为block 模式
ret = soc_setsockopt(soc_id , SOC_NBIO, &val, sizeof(val));
// 设置为异步模式,并且监听消息,这里设置了
// SOC_READ 表示有数据可读,也就是可以调用 soc_recv 读取
// SOC_WRITE 表示可以写,也就是可以通过soc_send来发送数据
// SOC_CONNECT 表示连接是否成功
// SOC_CLOSE 表示是否被关闭, 服务器端也可以是关闭连接的
val = SOC_READ|SOC_WRITE|SOC_CONNECT|SOC_CLOSE;
ret = soc_setsockopt(soc_id, SOC_ASYNC, &val, sizeof(val));待续
昨天说了下socket基本几个函数,还有常用的是域名解析函数。
// 通过域名获得ip地址
// is_blocking,是否阻塞,现在只支持none block,也最好用none block
// mod_id 如果没有立即获得,那么当查询成完毕,将向该mod 发送消息
// request_id 区分不同的DNS 查询结果。比如在同时查询两个以上,在返回的消息中,就可以通过id来进行区分,这个结果是哪一个查询结果
// addr 如果直接查询到结果,比如命中cache,那么ip地址直接返回
// len 返回的ip地址长度
// access_id 也存放在查询返回消息里面,但不知具体什么用
// nwk_account_id 接入点
kal_int8 soc_gethostbyname(kal_bool is_blocking,
module_type mod_id,
kal_int32 request_id,
const kal_char *domain_name,
kal_uint8 *addr,
kal_uint8 *addr_len,
kal_uint8 access_id,
kal_uint32 nwk_account_id);
接下来具体分析一个例子,socket 例子MTK,自带了一个,在EngineerModeSrc.c 和 EngineerModeSocketDemoApp.c 里,里面有好几个socket使用的例子,DNS,ECHO,DAYTIME,TRACERT。文件 EngineerModeSrc.c 里面主要是界面显示逻辑,EngineerModeSocketDemoApp.c 里面是真正的socket 逻辑代码。
在 EngineerModeSrc.c 里面,选择了相应的选项后,最终会走到函数 EntryEmSocketInProgress 显示正在进行网络连接的界面,它调用 EmSocketSendReq 函数 来简单区分,是选择了哪种应用。EmSocketSendReq 根据相关选择信息,调用mmi_soc_demo_app_request进行真正的socket处理。
// 这个函数主要是主要是根据不同配置,初始化全局信息。
// app_id, 是哪一种操作 NDS,HTTP等等
// account_id , grps 帐户id
// server_ip_address ip地址
// url url 地址,根据不同类型,确定使用ip地址还是url
// echo_txt ,如果是 ECHO,这个表示要发送的内容
// callback 操作的回调函数
int mmi_soc_demo_app_request(
mmi_soc_demo_app_enum app_id,
int account_id,
char server_ip_address[4],
char *url,
int url_len,
char *echo_text,
int echo_text_len,
mmi_soc_demo_app_rsp_t callback)
{
// soc_demo_transaction 是一个全局变量,存放当前信息
// 判断是否有连接正在进行
if (soc_demo_transaction)
{
kal_print("Transaction existed!!");
return EN_SOC_BUSY;
}
else
{
// 分配内存,如果出错调用 en_soc_output_result 通知注册的函数
// 同时释放相应内存,防止泄露。
if ((soc_demo_transaction = OslMalloc(sizeof(soc_demo_app_transaction_struct)) ) == NULL)
{
kal_print("No memory");
en_soc_output_result(EN_SOC_NO_MEMORY, NULL, 0);
return EN_SOC_NO_MEMORY;
}
else
{
// 分配收发内容的buffer
memset(soc_demo_transaction, 0, sizeof(soc_demo_app_transaction_struct));
if ((soc_demo_transaction->rcvd_buffer = OslMalloc(MAX_RCV_BUFFER_SIZE)) == NULL)
{
kal_print("No memory");
en_soc_output_result(EN_SOC_NO_MEMORY, NULL, 0);
return EN_SOC_NO_MEMORY;
}
else
{
if ((soc_demo_transaction->snd_buffer = OslMalloc(MAX_SND_BUFFER_SIZE)) == NULL)
{
kal_print("No memory");
en_soc_output_result(EN_SOC_NO_MEMORY, NULL, 0);
return EN_SOC_NO_MEMORY;
}
else
{
/* Set initial values to soc_demo_transaction */
memset((kal_int8*) soc_demo_transaction->rcvd_buffer, 0, MAX_RCV_BUFFER_SIZE);
memset((kal_int8*) soc_demo_transaction->snd_buffer, 0, MAX_SND_BUFFER_SIZE);
//计算接入点,具体下次分析
account_id = cbm_encode_app_id_data_account_id(account_id, app_id);
soc_demo_transaction->soc_demo_app_id = app_id;
soc_demo_transaction->nwt_acount_id = account_id;
// 保存相应信息
if (server_ip_address)
{
memcpy(soc_demo_transaction->server_ip_addr.addr, server_ip_address, 4);
soc_demo_transaction->server_ip_addr.addr_len = 4;
}
soc_demo_transaction->url = (kal_int8*) url;
soc_demo_transaction->url_len = url_len;
soc_demo_transaction->snd_counter = 0;
soc_demo_transaction->rcvd_counter = 0;
soc_demo_transaction->callback = callback;
if (echo_text)
{
if (echo_text_len > MAX_SND_BUFFER_SIZE)
{
memcpy(soc_demo_transaction->snd_buffer, echo_text, MAX_SND_BUFFER_SIZE);
soc_demo_transaction->snd_data_len = MAX_SND_BUFFER_SIZE;
}
else
{
memcpy(soc_demo_transaction->snd_buffer, echo_text, echo_text_len);
soc_demo_transaction->snd_data_len = echo_text_len;
}
OslMfree(echo_text);
}
if (en_soc_demo_app_create_socket() == KAL_FALSE)
{
en_soc_output_result(EN_SOC_NO_MEMORY, NULL, 0);
return EN_SOC_NO_MEMORY;
}
// 根据不同id,进行操作
switch (app_id)
{
case HTTP:
{
soc_demo_transaction->state = HTTP_DNS_QUERY;
return en_soc_demo_http_send_request();
}
case DNS:
{
(void)en_soc_demo_get_host_by_name(DNS, (kal_uint8*) soc_demo_transaction->url);
return EN_SOC_SUCCESS;
}
case DAYTIME:
{
soc_demo_transaction->server_ip_addr.port = SOC_DAYTIME_RESVD_PORT;
soc_demo_transaction->snd_data_len = 10; /* garbage data */
return en_soc_demo_udp_app_send_request();
}
case ECHO:
{
soc_demo_transaction->server_ip_addr.port = SOC_ECHO_RESVD_PORT;
return en_soc_demo_udp_app_send_request();
}
case TRACERT:
{
if (em_soc_icmp_init_soc() server_ip_addr.addr,0, MAX_SOCK_ADDR_LEN);
if (
em_soc_demo_app_get_addr_type((kal_uint8*)url, url_len, soc_demo_transaction->server_ip_addr.addr)
== SOC_ADDR_TYPE_DNAME )
{
soc_demo_transaction->state = HTTP_DNS_QUERY;
en_soc_demo_get_host_by_name(TRACERT, (kal_uint8*)soc_demo_transaction->url);
return EN_SOC_SUCCESS;
}
else
{
char str[64];
memset(str,0,64);
kal_sprintf(
str,
" %d.%d.%d.%d\n",
soc_demo_transaction->server_ip_addr.addr[0],
soc_demo_transaction->server_ip_addr.addr[1],
soc_demo_transaction->server_ip_addr.addr[2],
soc_demo_transaction->server_ip_addr.addr[3]
);
EmStartTraceRtResult(str);
soc_demo_transaction->state = REQ_SENT;
StartTimer(EM_GPRS_SOC_DEMO_APP_TIMER, SOC_DEMO_APP_POST_TIMEOUT, em_soc_icmp_timer_hdlr);
em_soc_icmp_send_hdlr(SOC_ICMP_SEND_NORMAL);
return EN_SOC_SUCCESS;
}
}
default:
{
en_soc_output_result(EN_SOC_UNKNOWN_APP, NULL, 0);
return EN_SOC_UNKNOWN_APP;
}
}
}
}
}
}
}
待续
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yanwuxufeng/archive/2010/09/0 7/5867693.aspx
发表评论
-
jdbc的那点小事
2012-01-20 09:04 826jdbc的那点小事 2011年01 ... -
BitmapData类介绍
2012-01-20 09:04 828BitmapData类介绍 2010年10月21日 注: ... -
Hibernate 学习 总结
2012-01-20 09:04 682Hibernate 学习 总结 2010年08月21日 ... -
右键添加显示隐藏文件(转贴)
2012-01-19 14:10 861右键添加显示隐藏文件(转贴) 2012年01月15日 右 ... -
教你用记事本做整人的另类签名
2012-01-19 14:10 821教你用记事本做整人的另类签名 2011年12月24日 今 ... -
S7-300 PLC的串口无线通讯在火电厂污水处理中的应用
2012-01-19 14:10 797S7-300 PLC的串口无线通讯 ... -
IIS32位和64位切换
2012-01-19 14:10 664IIS32位和64位切换 2011年12月22日 X64 ... -
两平台下的自动登录telnet设置
2012-01-19 14:10 770两平台下的自动登录telnet设置 2011年12月28日 ... -
CPU与内存都是什么?
2012-01-17 03:58 864CPU与内存都是什么? 2010 ... -
IO输入输出
2012-01-17 03:58 670IO输入输出 2011年04月26日 io输入与输出 ... -
关于内存的
2012-01-17 03:58 736关于内存的 2010年10月04日 前端总线是一个很重要 ... -
“0×00402804”指令引用的“0×0000009C”内存 该内存不能为“writen” 这是怎么回事
2012-01-17 03:58 809“0×00402804”指令引用 ... -
内存不能为read正确修复方法
2012-01-17 03:58 748内存不能为read正确修复方法 2010年06月03日 ... -
IP组播技术综述二
2012-01-16 02:49 716IP组播技术综述二 2011 ... -
写给Linux内核新手-关于Linux内核学习的误区(转自ChinaUnix.net)
2012-01-16 02:49 915写给Linux内核新手-关于L ... -
Java加密和数字签名 5数字证书
2012-01-16 02:48 897Java加密和数字签名 5数 ... -
什么是CGI、FastCGI、PHP-CGI、PHP-FPM、Spawn-FCGI?
2012-01-16 02:48 627什么是CGI、FastCGI、PHP-CG ...
相关推荐
MTK_SOCKET.pdf 官方文档 MTK_SOCKET.pdf 官方文档 MTK_SOCKET.pdf 官方文档
在MTK上实现socket下载 代码精简,注释详细。
MTK连接socket的源代码
MTK 10A socket编程相关经验分享MTK 10A socket编程相关经验分享
关于MTK socket编程的一些经验关于MTK socket编程的一些经验关于MTK socket编程的一些经验关于MTK socket编程的一些经验关于MTK socket编程的一些经验关于MTK socket编程的一些经验
介绍了MTK的联网基础知识,包括socket、wps
MTK_Socket_http连接方式编程总结
mtk socket编程,套节字创建,连接,接受,发送接口
文档打开密码是84149961konka
MTK SOCKET API 文档 --- 各种函数介绍、参数解析,是入门MTK SOCKET编程的好资料!
MTK socket source code,use for MTK newer to learn MTK ptotocol curses.you can use this to learn HTTP,TCPIP related knowledget.
这是一个关于MTK平台上联网的代码,自己学习的时候学的一个测试代码。。
MTK平台用Socket实现HTTP请求总结
MTK平台用Socket实现HTTP请求总结
测试程序 mtk 走cmwap 连接socket
RVDS 3.1 mtk mre_sms_sample
详细描述了MTK平台下socket接口的使用方法,MTK网络编程的最详细的文档
MTK 平台的socket文档,主要介绍信号流程等。内部资料,。
本代码主要根据6225平台搭建的,介绍了socket联网的过程,谢谢~~