提到聊天程序,一般都會想到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,不但可以保存,還可以多個用戶同時進行,通信實現了,多個用過戶通信也就沒有問題,還可以加入一些聲音,圖片,或者視頻,筆者只是拋磚引玉,如果以后有足夠時間,筆者會加入進去的
沒上傳過源碼,不知道這樣行不行
http://files.cnblogs.com/fish124423/sumthesun.rar