北京理工大学 20981 陈罡
现在gprs上网是要花钱的,我们费了好大劲做了个5m周刊,可以给用户省钱,不需要联gprs,只
需要通过互联网下载,然后拷贝到手机里面就可以看了。还是很多朋友提出,为什么不做个联网
的版本。
这已经开始引起我们的注意,或许经过很长时间中国移动对用户习惯的培养,用户对于这种免费的,
只需要动动手从互联网上下载到资源拷贝到到手机里面使用的模式已经不感兴趣了?
用户可以接受花点钱,下载到手机里面看了吗?
又或许是现在90%的第三方手机应用都是要连接gprs的,已经误导了用户,凡是手机应用就要联gprs,就要花一些流量费;而没有流量费的软件反而被认为是奇怪的程序。呵呵,这就不得而知了。
言归正转,如何让小明可以联结gprs,并且访问internet上的服务器呢?
其实很简单,linux下面的socket如何使用,在a1200手机上面也基本雷同。不过还是有一些特别
的地方的,主要是gprs拨号的问题,需要等待手机先“拨号上网”,等到连接上了,还需要做一个
绑定的动作,把当前的ppp拨号于创建的socket句柄绑定起来,再往下就是常规的socket操作了。
呵呵,说了这么多,还是来点实际的,结合代码讲解一下吧:
#include
#include // hoho,这个文件就是关键了,可惜moto的政策所限
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//需要连接的端口号和ip地址
#define SOCK_PORT 3210
#define SOCK_ADDR "221.221.8.226"
using namespace std ;
//发送数据函数,明眼人一眼就可以看出,moto上的socket原来可以支持异步发送
//呵呵,这样应该效率会更高一些
int send_buf(int soc, const u_char *buff, int bufflen)
{
INT32 to_send = bufflen ;
INT32 n;
do {
n = send(soc, buff, bufflen, 0) ;
if(n < 0) {
if(errno == EINTR) continue ;
else return -1 ;
}
to_send -= n ;
} while( to_send > 0 );
return to_send ;
}
int main(int argc, char * argv[])
{
INT32 sock ;
int napi_fd = 0 ;
int link_id = 0 ;
UINT32 prof_count = 5 ;
INT8 prof_lst[NAPI_MAX_PROFILE_NAME_LENGTH * prof_count] ;
INT8 prof_select[NAPI_MAX_PROFILE_NAME_LENGTH] ;
struct hostent *hp ;
struct sockaddr_in sin ;
int ret ;
char buf[] = "hello" ;
// 读取接入点设置,一般来说moto内置的接入点有三种:
// “java网络接入”,“移动梦网”,“连接互联网”
// 本质上,“java网络接入”和“连接互联网”均属于cmnet连接,hoho,1k 0.03元喔!
// “移动梦网”需要经过10.0.0.172网关中转,比较繁琐一些,在此我们选择
//“连接互联网”的接入方案。
NAPI_ListAllProfile(prof_lst, &prof_count);
// 初始化NAPI
napi_fd = NAPI_Init( NAPI_DETAIL_STATE_FLAG ) ;
// 这里就把刚刚枚举过的接入点取出来了,放到prof_select变量中
memset(prof_select, 0, NAPI_MAX_PROFILE_NAME_LENGTH) ;
strcpy((char *)(prof_select),
(char *)(prof_lst+2*NAPI_MAX_PROFILE_NAME_LENGTH)) ;
printf("%s\n", prof_select) ;
// 开始拨号罗
if(napi_fd >= 0) link_id = NAPI_OpenLink(prof_select) ;
// 稍微等待一会儿,就可以连上了,这里偶等了5秒钟
sleep(5) ;
// 用常规手法创建socket
sock = socket(PF_INET, SOCK_STREAM, 0) ;
if(sock < 0) {
cout<<"socket create failed..."< if(napi_fd >= 0) NAPI_Fini() ;
return -2 ;
}
// 把socket绑定到pppoe的拨号上去,告诉系统收发数据用哪个网卡什么的
ret = NAPI_BindSocket2Link( sock, link_id ) ;
if(ret != 0) {
cout<<"socket bind with ppp link failed..."< close(sock) ;
if(napi_fd >= 0) NAPI_Fini() ;
return -3 ;
}
// 例牌的初始化sin地址
sin.sin_family = PF_INET ;
sin.sin_port = htons(SOCK_PORT) ;
sin.sin_addr.s_addr = inet_addr((const char *)(SOCK_ADDR));
// 如果初始化失败,则调用域名解析,看看能否得到ip地址
if (sin.sin_addr.s_addr == (unsigned int)(-1) ) {
hp = gethostbyname((const char *)(SOCK_ADDR));
UINT8 retry_count = 1;
while ((hp == NULL) && (TRY_AGAIN == h_errno) && (retry_count<=6)) {
sleep(3);
hp = gethostbyname((const char *)(SOCK_ADDR));
retry_count ++;
cout<<"retry ..."< }
if (hp == NULL) {
close(sock);
return -4 ;
}
memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
}
// 开始连接
cout<<"connect ..."< if (connect(sock, (struct sockaddr *)&sin, sizeof(struct sockaddr)) < 0) {
if((errno != EINPROGRESS) && (errno != EINTR)) {
cout<<"connect failed"< close(sock);
}
}
// 剩下就是发送数据了,偶只测试到这里,就已经觉得一切明朗了。
// 相信大家也有同感吧?剩下的就是纯的socket操作了。
send_buf(sock, (u_char *)(buf), sizeof(buf)) ;
sleep(1) ;
send_buf(sock, (u_char *)(buf), sizeof(buf)) ;
sleep(1) ;
send_buf(sock, (u_char *)(buf), sizeof(buf)) ;
sleep(1) ;
// 关闭socket
shutdown(sock, 0) ;
// 释放NAPI
if(napi_fd >= 0) NAPI_Fini() ;
return 0 ;
}
服务器偶是利用iptables,在服务器上面做了个nat穿透,把所有发给服务器的测试端口的数据
转发给我的机器,呵呵,这样做可能会有问题,虽然整个数据收发过程没有问题,但是退出的时候
虽然小明上已经退出了,但是服务器这边还是没有收到退出的信号,难道shutdown(xxx)这个函数
之后还要跟上个close(xxx)?我记得pc上写socket的时候不需要啊,或许是nat引起的问题吧。
不深究了,等到要用的时候再说吧。相信根据以上的代码封装一个socket engine还是很轻松的。
阅读(3416) | 评论(3) | 转发(0) |