在Silverlight中使用Socket进行通信(3)简单的文本聊天工具

在上一篇的基础上,晚上我又尝试了一下做个聊天工具,有个定时取消息的过程解决不好,明天再研究一下,在这个文本聊天的基础上,稍加扩展就可以进行视频聊天了,下一篇将会做silverlight视频聊天的DEMO.

整体效果是

    

 

还是从服务端说起,服务端做中转消息用,为了模拟聊天情景,服务端简单写了一个实体用来缓存聊天内容 

代码
public   class  UserSocket 
    { 
        
public   string  UserName {  set get ; } 
        
public   string  PartnerName {  set get ; }         
        
public   string  Message {  set get ; } 
        
public  DateTime StoreTime {  set get ; } 
    }

  

然后在主程序中声明一个List<UserSocket>对象存储聊天内容。

static List<UserSocket> listUserSocket = new List<UserSocket>();

当聊天双方给对方发送消息时,可以通过预先设定的字符串格式,比如采用 - 来将发送者,接受者,聊天内容组合起来发送到服务器进行解析和存储。

 代码

byte [] bytData  =   new   byte [ 1024 ]; 
                
int  receivedLength  =  client.Receive(bytData); 
                
string  strReceive  =  System.Text.Encoding.UTF8.GetString(bytData,  0 , receivedLength); 

                listUserSocket.Add(
new  UserSocket() 
                { UserName 
=  strReceive.Split( ' - ' )[ 0 ], 
                    PartnerName 
=  strReceive.Split( ' - ' )[ 1 ], 
                    Message 
=  strReceive.Split( ' - ' )[ 2 ], 
                    StoreTime
= DateTime.Now });

 

 当客户端A定时来服务器请求发给自己的消息时,服务器就会在listUserSocket中查找到发送给A的消息并清除此消息。

 代码

UserSocket userSocket  =  listUserSocket.Where(m  =>  m.PartnerName  ==  strReceive.Split( ' - ' )[ 0 ]).FirstOrDefault(); 
                listUserSocket.RemoveAll(m 
=>  m.PartnerName  ==  strReceive.Split( ' - ' )[ 0 ]);

 

 关键代码:

由于silverlight中没有提供监听socket请求的方法,只能作为客户端跟服务器进行交互,所以在客户端我们可以预先定义一个Socket

 

private   Socket clientSocket  =   null ;  

 及远程通信的IP和端口 

private   const   string  SERVER_IP  =   " 127.0.0.1 "
        
private   const   int  SERVER_PORT  =   4530 ;

 我们可以为这个clientSocket建立起连接 

代码
clientSocket  =   new  Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
            SocketAsyncEventArgs socketEventArg 
=   new  SocketAsyncEventArgs() 
            { 
                RemoteEndPoint 
=   new  IPEndPoint(IPAddress.Parse(SERVER_IP), SERVER_PORT) 
            }; 
            socketEventArg.Completed 
+= new  EventHandler < SocketAsyncEventArgs > (socketEventArg_Completed); 
            clientSocket.ConnectAsync(socketEventArg);

 

鉴于sl的事件处理是异步的,所以 

代码
//  连接成功后 开始发送 
         void  socketEventArg_Completed( object  sender, SocketAsyncEventArgs e) 
        { 
            
if  (e.SocketError  ==  SocketError.Success) 
            { 
                
// AddText("已连接服务器!"); 
                 string  strSend  =  USERNAME + " - " + PARTNERNAME + " - " + MESSAGE; 
                
byte [] bytSend  =  Encoding.UTF8.GetBytes(strSend); 
                SocketAsyncEventArgs socketArg 
=   new  SocketAsyncEventArgs(); 
                socketArg.Completed 
+=   new  EventHandler < SocketAsyncEventArgs > (socketArg_Completed); 
                socketArg.SetBuffer(bytSend, 
0 , bytSend.Length); 
                clientSocket.SendAsync(socketArg); 
                
// AddText("向服务器发送信息...");                
            }            
        }

  

当发送成功后,就可以向服务器取消息啦 

代码
void  socketArg_Completed( object  sender, SocketAsyncEventArgs e) 
        { 
             
// 发送成功 
             if  (e.SocketError  ==  SocketError.Success) 
            { 
                AddText(
" 已经将自己的IP和聊天对象发送到服务器 " ); 
            } 
            timer 
=   new  Timer( new  TimerCallback(StartReceive),  null 500 1000 );            
        }

  

定时取消息的方法,也是异步的 

代码
void  StartReceive( object  o) 
        { 
            
byte [] byteReceive = new   byte [ 102400 ]; 
            SocketAsyncEventArgs socketReceiveArg 
=   new  SocketAsyncEventArgs(); 
            socketReceiveArg.Completed 
+=   new  EventHandler < SocketAsyncEventArgs > (socketReceiveArg_Completed); 
            socketReceiveArg.SetBuffer(byteReceive, 
0 , byteReceive.Length); 
            clientSocket.ReceiveAsync(socketReceiveArg); 
        } 
        
void  socketReceiveArg_Completed( object  sender, SocketAsyncEventArgs e) 
        { 
            
if  (e.SocketError  ==  SocketError.Success) 
            { 
                
byte [] byteReceive  =  e.Buffer; 
                
string  strText  =  System.Text.Encoding.UTF8.GetString(byteReceive,  0 , byteReceive.Length); 
                AddText(
" 成功接收到服务器回传的消息 "   +  strText); 
            } 
        } 

 可以看到,从连接到发送,再到接收,我们用的是一个socket实例来完成的,也就是说在silverlight中只需要连接一次socket就可以顺利进行后续操作了。

服务端的监听

服务端的监听socket 跟客户端的不同,监听是一个socket实例,发送和接收则是另外一个代表客户端的实例。

首先还是需要指定监听IP和端口及使用的Socket

 

private   const   string  SERVER_IP  =   " 127.0.0.1 "
        
private   const   int  SERVER_PORT  =   4530
        
static  Socket listener;

  

同样,也需要进行策略文件的验证 

代码
#region  Start The Policy Server 
                PolicySocketServer StartPolicyServer 
=   new  PolicySocketServer(); 
                Thread th 
=   new  Thread( new  ThreadStart(StartPolicyServer.StartSocketServer)); 
                th.IsBackground 
=   true
                th.Start(); 
                
#endregion

 

 然后开始监听 

代码
IPEndPoint localEndPoint  =   new  IPEndPoint(IPAddress.Parse(SERVER_IP), SERVER_PORT); 
                listener 
=   new  Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
                listener.Bind(localEndPoint); 
                listener.Listen(
- 1 ); 
                Console.WriteLine(
" 等待客户端连接... " ); 
                
while  ( true
                { 
                    Socket clientSocket 
=  listener.Accept(); 
                    
if  (clientSocket.Connected) 
                    {                     
                        Thread myThread 
=   new  Thread( new  ParameterizedThreadStart(SocketThread)); 
                        myThread.Start(clientSocket); 
                    } 
                } 

 

 当监听到有客户端连接时,就另外开启线程进行处理,这个操作同时也确定了需要多个socket实例进行应答。 

代码
static   void  SocketThread( object  clientSocket)   
        { 
            
try  
            { 
                Socket client 
=  (Socket)clientSocket; 
                IPEndPoint address 
=  (IPEndPoint)client.RemoteEndPoint; 

                
byte [] bytData  =   new   byte [ 1024 ]; 
                
int  receivedLength  =  client.Receive(bytData); 
                
string  strReceive  =  System.Text.Encoding.UTF8.GetString(bytData,  0 , receivedLength); 

                listUserSocket.Add(
new  UserSocket() 
                { UserName 
=  strReceive.Split( ' - ' )[ 0 ], 
                    PartnerName 
=  strReceive.Split( ' - ' )[ 1 ], 
                    Message 
=  strReceive.Split( ' - ' )[ 2 ], 
                    StoreTime
= DateTime.Now }); 
                Console.WriteLine(
" "   +  strReceive.Split( ' - ' )[ 0 +   " 】通过【 "   +  address.Address.ToString()  +   " : "   +  address.Port.ToString()  +   " 】登录了服务器,并给【 "   +  strReceive.Split( ' - ' )[ 1 +   " 】留言如下: " ); 
                Console.WriteLine(strReceive.Split(
' - ' )[ 2 ] + " ,当前服务器消息数量【: " + listUserSocket.Count.ToString() + " " ); 

                UserSocket userSocket 
=  listUserSocket.Where(m  =>  m.PartnerName  ==  strReceive.Split( ' - ' )[ 0 ]).FirstOrDefault(); 
                listUserSocket.RemoveAll(m 
=>  m.PartnerName  ==  strReceive.Split( ' - ' )[ 0 ]); 
                
if  (userSocket  !=   null
                { 
                    client.Send(System.Text.Encoding.UTF8.GetBytes(userSocket.Message)); 
                    Console.WriteLine(
" "   +  userSocket.PartnerName  +   " 】取走了消息【 "   +  userSocket.Message  +   " 】,当前服务器消息数量【: " + listUserSocket.Count.ToString() + " " ); 
                } 
            } 
            
catch  
            {   } 
        } 



     本文转自wengyuli 51CTO博客,原文链接:http://blog.51cto.com/wengyuli/587562,如需转载请自行联系原作者



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值