在上一篇的基础上,晚上我又尝试了一下做个聊天工具,有个定时取消息的过程解决不好,明天再研究一下,在这个文本聊天的基础上,稍加扩展就可以进行视频聊天了,下一篇将会做silverlight视频聊天的DEMO.
整体效果是
还是从服务端说起,服务端做中转消息用,为了模拟聊天情景,服务端简单写了一个实体用来缓存聊天内容
{
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>();
当聊天双方给对方发送消息时,可以通过预先设定的字符串格式,比如采用 - 来将发送者,接受者,聊天内容组合起来发送到服务器进行解析和存储。
代码
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的消息并清除此消息。
代码
listUserSocket.RemoveAll(m => m.PartnerName == strReceive.Split( ' - ' )[ 0 ]);
关键代码:
由于silverlight中没有提供监听socket请求的方法,只能作为客户端跟服务器进行交互,所以在客户端我们可以预先定义一个Socket
及远程通信的IP和端口
private const int SERVER_PORT = 4530 ;
我们可以为这个clientSocket建立起连接
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("向服务器发送信息...");
}
}
当发送成功后,就可以向服务器取消息啦
{
// 发送成功
if (e.SocketError == SocketError.Success)
{
AddText( " 已经将自己的IP和聊天对象发送到服务器 " );
}
timer = new Timer( new TimerCallback(StartReceive), null , 500 , 1000 );
}
定时取消息的方法,也是异步的
{
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 int SERVER_PORT = 4530 ;
static Socket listener;
同样,也需要进行策略文件的验证
PolicySocketServer StartPolicyServer = new PolicySocketServer();
Thread th = new Thread( new ThreadStart(StartPolicyServer.StartSocketServer));
th.IsBackground = true ;
th.Start();
#endregion
然后开始监听
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实例进行应答。
{
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
{ }
}