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

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

整体效果是

image

image image

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

 

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

 

 

然后在主程序中声明一个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), null5001000);            
        }

 

 

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

 

代码
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 
            {   } 
        } 

  

源代码:https://files.cnblogs.com/wengyuli/Socket.rar

posted @ 2010-07-15 01:21  翁玉礼  阅读(4383)  评论(52编辑  收藏  举报