在Silverlight中使用Socket进行通信(3)简单的文本聊天工具
在上一篇的基础上,晚上我又尝试了一下做个聊天工具,有个定时取消息的过程解决不好,明天再研究一下,在这个文本聊天的基础上,稍加扩展就可以进行视频聊天了,下一篇将会做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
{ }
}