提到聊天程序,一般都会想到socket,一边发,一边发,简单而又威武。
wpf支持绑定,支持类似动态刷新,而且wcf支持的服务用户更多,通信上,更是能做到伪peer to peer(就是p2p....笔者对这个一直很感兴趣) 的通信方式,说他是伪peer to peer方式,是因为可以把wcf服务当一个中转站,然后让每一个用户直接通信,而避免中转!只是个想法。。。。
好了,不扯皮了,三个工程,server host client
server端: 通信接口
[ServiceContract(SessionMode = SessionMode.NotAllowed)] public interface IHost { [OperationContract] string Test(); [OperationContract] bool ConnectCumm(string commId); [OperationContract] void ClientSend(string commId, string str); [OperationContract] List<string> GetHostMessage(string id); }
server实现
public class HostSvc:IHost { public string Test() { return "hello world!"; } /// <summary> /// 添加一个客户端连接 /// </summary> /// <param name="commId"></param> /// <returns></returns> public bool ConnectCumm(string commId) { var data = new FishComm(commId); return ListenComm.TryAdd(data); } public void ClientSend(string commId,string str) { ListenComm.ClientWriteMessage(commId,str); } public List<string> GetHostMessage(string id) { var data = ListenComm.GetMessage(id); return data; } }
static class ListenComm是自己写的缓存的静态类,里面写了简单的保存消息和服务器端发送消息
/// <summary> /// 客户端获取服务器的信息列表 /// </summary> /// <param name="id"></param> /// <returns></returns> public static List<string> GetMessage(string id) { var data = _list.ContainsKey(id) ? _list[id].FishRecMessage : null; List<string> d = new List<string>(); foreach (var temp in data) { d.Add(temp); } data.Clear(); return d; } /// <summary> /// 服务器获取某一个客户端的信息列表 /// </summary> /// <param name="id"></param> /// <returns></returns> public static List<string> SendMessage(string id) { return _list.ContainsKey(id) ? _list[id].RecMessage : null; } /// <summary> /// 客户端写消息 /// </summary> /// <param name="id"></param> public static void ClientWriteMessage(string id, string str) { var data = GetList.Find(p => p.Id == id); if (data == null) return; data.FishSendMessage.Add(data.FishId + ":" + str); FishCWriteMessage(null, new FishEnventArgs(data)); } /// <summary> /// 服务器写消息 /// </summary> /// <param name="id"></param> public static void HostWriteMessage(string id, string str) { var data = GetList.Find(p => p.Id == id); if (data == null) return; data.FishRecMessage.Add(str); FishHWriteMessage(null, new FishEnventArgs(data)); }
总体思路是这样的,客户端和服务器各自 有一个List<string> 一个用于保存客户端的消息队列,一个用于保存服务器发送给客户端的消息,
客户端一直写消息,同时每隔一段间隔就会从服务器去消息,客户端有个timer定时取消息,当取了消息后,清空客户端的消息队列,就相当于双方通信了
public class ClientVM : INotifyPropertyChanged { const string id = "爱喝可乐"; DispatcherTimer dt; private ICommand _start; public ICommand Start { get { if (_start == null) { _start = new DelegateCommand(p => { new HostSvc.HostClient().ConnectCumm(id); IsFree = false; dt = new DispatcherTimer(); dt.Interval = new TimeSpan(500); dt.Tick += new EventHandler(dt_Tick); dt.Start(); }, o => IsFree); } return _start; } } void dt_Tick(object sender, EventArgs e) { var data = new HostSvc.HostClient().GetHostMessage(id); if (data != null) { foreach (var temp in data) { RecText = "服务器:" + temp; } } } private ICommand _send; public ICommand Send { get { if (_send == null) { _send = new DelegateCommand(p => { new HostSvc.HostClient().ClientSend(id, SendText); SendText = ""; //发送消息 }, o => true); } return _send; } } private bool _isFree = true; public bool IsFree { get { return _isFree; } set { if (_isFree != value) { _isFree = value; OnPropertyChange("IsFree"); } } } private string _recText; public string RecText { get { return _recText; } set { _recText += value+"\n"; OnPropertyChange("RecText"); } } private string _sendText; public string SendText { get { return _sendText; } set { if (_sendText != value) { _sendText = value; OnPropertyChange("SendText"); } } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChange(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }
这是客户端的方法
下面是xmal
<Window x:Class="Client.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="408" Width="633"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="30"/> <RowDefinition Height="280" /> <RowDefinition /> </Grid.RowDefinitions> <Button Command="{Binding Start}" Content="连接服务器" Width="80" Margin="0,0,422,0"></Button> <Grid Grid.Row="1"> <Grid.ColumnDefinitions> <ColumnDefinition Width="120"></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <ListView ></ListView> <TextBox Grid.Column="1" Text="{Binding RecText}"/> </Grid> <TextBox Grid.Row="2" Text="{Binding SendText,Mode=TwoWay}" Height="30" Margin="0,6,98,16" /> <Button Grid.Row="2" Command="{Binding Send}" Height="30" Content="发送" Width="80" Margin="486,6,12,15"/> </Grid> </Window>
服务器端会有一个列表,每一个用户连接,就会记录连接用户的信息,然后就会有一个列表了,想给那个发就给那个发了
一个很简单的demo,只是抛砖引玉的意思,host要用管理员身份启动,然后客户端连接,然后进行通信,里面肯定有很多bug,只是一个简单的demo,
通信记录没有保存,只是一个临时的list进行暂存,还有其他比较好的方式,比如xml或者txt,不但可以保存,还可以多个用户同时进行,通信实现了,多个用过户通信也就没有问题,还可以加入一些声音,图片,或者视频,笔者只是抛砖引玉,如果以后有足够时间,笔者会加入进去的
没上传过源码,不知道这样行不行
https://files.cnblogs.com/fish124423/sumthesun.rar