在WINCE中基于ActiveSync的Socket通信 c#

一、序

之前做WINCE的项目,涉及到PCPDA通信的时候,采用的是ActiveSync的通信方式,在PC上采用RAPI函数对PDA中的数据或文件进行控制,这种方式是单项的,与PDA中的程序基本无联系,在扩展性和功能性方面存在一些局限性。

采用Socket通信是一种不错的选择,但由于应用在特殊行业,不能使用WIFI模块和3G模块,PDA上没有分配IP地址,好像并不具备Socket通信的条件。

在查找了一些资料后发现ActiveSync通信其实是基于TCP的连接方式,既然是TCP,那么一定有地址和端口。

PDA 程序中运行:
Dns.GetHostEntry(Dns.GetHostName()).AddressList[ 0 ].ToString();
发现了“ 192.168.55.101 ”这个地址。
运行:
Dns.GetHostEntry(“PPP_PEER”).AddressList[ 0 ].ToString();
发现了“ 192.168.55.100 ”这个地址。


二、基于ActiveSyncSocket通信

PDAPC通过ActiveSync的方式连接后,PDA会得分配到192.168.55.101IP地址,PC会分配到192.168.55.100IP地址,值得注意的是PC上的这个IP地址是无法通过Ipconfig指令查找到的,也无法ping通,无法Bind,不算是一个真正意义上的IP地址。而且任何一台PDA通过ActiveSync连接后,地址都相同(PC 192.168.55.100PDA 192.168.55.101)。

初步确定采用 PC 作为 Socket Server 端, PDA 作为 Socket Client 端进行数据通信这种方式后(注 1 ),就着手开始编写代码。

2.1 Socket Server端(PC服务器)

代码与普通 Socket Server 代码没什么两样,值得注意的是 Bind IP 地址不能为 192.168.55.100 ,也不能为该计算机的网络 IP 地址,而需要绑定“ 127.0.0.1 ”。
IPEndPoint iep  =   new  IPEndPoint(IPAddress.Parse(“ 127.0 . 0.1 ”),  10000 );
m_Socket 
=   new  Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_Socket.Bind(iep);

2.2Socket Client端(PDA WINCE

代码与普通 Socket Client 代码差不多,连接的地址设置为“ 192.168.55.100 ”,可采用这样的方式编写:
string  m_ServerIp  =   "" ;
try
{
    m_ServerIp 
=  Dns.GetHostEntry(“PPP_PEER”).AddressList[ 0 ].ToString();
}
catch  {
    m_ServerIp 
=   " 192.168.55.100 " ;
}
IPAddress serverIp 
=  IPAddress.Parse(m_ServerIp);
int  serverPort  =   10000 ;
IPEndPoint iep 
=   new  IPEndPoint(serverIp, serverPort);
m_SocketConnection 
=   new  Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_SocketConnection.Connect(iep);
另外值得注意的是 Socket Connected 属性,在 PC 端的 Socket Server 服务关闭( Close )的情况下, PDA 只要 Connect Connected 属性都会变成 true 。因此不能仅仅通过 Connected 属性来判断 Socket 是否连接正常,需要单独开一个线程,采用心跳包的方式进行检测。最好在 Socket.Connect 后执行一下 Socket.Receive ,如果成功则说明网络正常(注 2 ),不成功说明网络断开。为防止 Receive 阻塞, PC 服务端程序在与 PDA 连接后应立即发送一个短字节给客户端,让客户端接收。

 

三、Socket涉及到的结构字节数组转换

Socket通信中涉及到很多结构与字节数组的转换,在WINDOW上运行正常的程序在WINCE中会报不支持.的异常。代码如下:

[StructLayout(LayoutKind.Sequential, CharSet  =  CharSet.Auto)]
public   struct  SocketMsg
{
        
public  SocketMsgType MsgId;  // 枚举类型
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst  =   20 )]
        
public   string  MsgDatetime;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst 
=   100 )]
        
public   string  MsgContent;
}
SocketMsg msg 
=   new  SocketMsg();
Msg.MsgId 
=   0 ;
Msg.MsgDatetime 
=  DateTime.Now.ToString( " yyyy-MM-dd HH:mm:ss " );
Msg.MsgContent 
=   "" ;
private   byte [] MsgStructToByte(SocketMsg msg)
{
     
int  size  =  Marshal.SizeOf(msg);
     System.IntPtr ptr 
=  Marshal.AllocHGlobal(size);
     
try
     {
          Marshal.StructureToPtr(msg, ptr, 
false );
          
byte [] ba  =   new   byte [size];
          Marshal.Copy(ptr, ba, 
0 , ba.Length);
          
return  ba;
      }
      
finally
      {
          Marshal.FreeHGlobal(ptr);
      }
 }
以上代码在 WINDOW 下运行正常,但是在 WINCE 运行到 StructureToPtr 时报异常,异常显示不支持 ByValTStr 这种方式。为解决该问题,需要改变该结构定义。
[StructLayout(LayoutKind.Sequential, CharSet  =  CharSet.Auto)]
public   struct  SocketMsg
{
        
public  SocketMsgType MsgId;  // 枚举类型
        [MarshalAs(UnmanagedType. ByValArray, SizeConst  =   20 )]
        
public   byte [] MsgDatetime; // 注3
        [MarshalAs(UnmanagedType. ByValArray, SizeConst  =   100 )]
        
public   byte [] MsgContent;
}
SocketMsg msg 
=   new  SocketMsg();
msg.MsgId 
=   0 ;
msg.MsgDatetime 
=  Encoding.ASCII.GetBytes(DateTime.Now.ToString( " yyyy-MM-dd HH:mm:ss " ) + "   " );
msg.MsgContent 
=   new   byte [ 100 ];
需要说明的是 +" " ,因为MsgDatetime数组定义为 20 字节 , ”2011-03-31 -15:30:30” 19 位,因此需要补一个空格凑足 20 位, StructureToPtr 时就不会报异常了,同样道理在给 MsgContent 赋值的时候也应该注意该问题。


四、另外一些补充说明

OpenNETCF 是一个很好的开发库,但是在WINCE中,由于一些DLL不存在,因此需要有选择的使用。例如因为没有Cellcore.dll这个文件(Windows mobile支持),在WINCE中无法使用 OpenNETCF.Net Namespace 中的 ConnectionManager Class 来管理网络连接状态。

 

附:

以上代码的环境为:

PC端:WIN2003ActiveSync4.5F2.0

PDA端:WINCE5.0CF2.0

 

1Google里资料说PDA作为Socket Server PC作为Socket Client的好像无法实现,因此就没有进行测试,有兴趣的朋友可测试一下。

2:不能用Socket.Send,测试发现在Socket Server服务关闭的情况下,ConnectSend有时也会成功

3:在WINCE char默认为unicode16位,因此在定义结构体时最好采用byte

 

 

你可能感兴趣的:(在WINCE中基于ActiveSync的Socket通信 c#)