在上一篇的基础上,晚上我又尝试了一下做个聊天工具,有个定时取消息的过程解决不好,明天再研究一下,在这个文本聊天的基础上,稍加扩展就可以进行视频聊天了,下一篇将会做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,如需转载请自行联系原作者