MSNPSharp项目地址: sharp 源代码svn地址: 我们直入正题MSNPSharp的消息发送机制的确和大部分人想的不太一样一般人概念上发送消息就一个步骤调用自己写的 SendXXXX 函数(该函数实现向某个用户发送网络数据)就可以直接实现向对方通信了其实这样做要有个前提那就是你的SendXXX函数(下文简称Send)在被调用的时候要么它能同步地(是的同步很重要)找到你要的目标用户并且立即建立连接发送数据要么它就把和对方握手缓沖向目标用户建立连接成功之前输入数据这些功能封装了以至于调用者根本看不见这些步骤然而遗憾的是为了能让程序员更灵活地控制发送消息的各个步骤MSNPSharp的SBMessageHandlerSendtextMessage函数设计不符合以上所有假设换言之你必须自己处理连接中的所有过程 很多人看到这里可能会觉得这样做实在太麻烦其实不然只要你了解了MSN向对方发送消息的整个过程就会觉得很简单了 要使用MSNPSharp向你的好友发送消息首先必须建立一个Conversation对象这个对象可以通过调用Messenger类的CreateConversation函数获得 建立了Conversation就可以通话了么?答案是否定的因为这个Conversation这时候只有你一个人就好比你要向一个朋友通电话你直接拿起话筒就能和对方说话么? 于是下一步我们该干什么呢?让我们回到通电话的那个例子上来我们拿起话筒理所当然做的第二件事情就是——拨号MSNPSharp也一样你得拨号把对方邀请到你的Conversation里面来这很简单调用你先前得到的那个Conversation对象的Invite函数那个函数只有一个参数就是目标好友的Windows Live 帐号(前提是他没有Block你)或者干脆就是你目标好友的Contact对象 完事了么?很明显没有你拨号了之后还得等人接了才能通话当然在现实生活中完成这个动作很简单你只需要拿着话筒等待就可以了因为拨号的这个过程是线性的(或者说是同步的)动作一个接一个地发生但是写程序就没有那么走运了要知道Invite对方直到对方响应可能是一个很长的过程如果是同步的话那么可能需要等待很长的时间以至于你不得不建立多条线程来处理每一个Invite所以MSNPSharp采用的是异步+事件通知的设计Invite后Invite函数立即返回当对方接听后会在ConversationSwitchBrard触发一个事件ContactJoined 这个时候你才可以用 ConversationSwitchBoardSendTextMessage向对方发送消息 通常很多人在ContactJoined事件之前就向对方调用SendTextMessage那结果只有一个发送失败如果在ContactJoined事件之前UI又有几条消息要被指定发送那么建议先用个队列或数组之类保存这些消息等ContactJoined事件触发了之后再发送 事情看上去大功告成了但是不得不告诉各位一个坏消息提供通话服务的MSN电信局很吝啬如果你俩通话过程中超过秒到一分钟一言不发它会把你们的通话掐断(事实上应该是如果对方使用的是官方的MSN客户端对方主动退出据测试)这个时候 ConversationSwitchBard 的 ContactLeft 事件会被触发通知你对方用户退出ConversationConversationSwitchBoardContactsCount属性会自减表示在此Conversation里面的Contact少了一个(如果一个Conversation里面所有对方用户都退出了会触发AllContactsLeft事件这时可以直接调用ConversationSwitchboardClose()关闭Conversation) 这时问题就来了如果我想向一个因为长时间不发送消息而退出的用户重新发送消息该怎么办呢?恩是的重新调用Messanger CreateConversation再建立一个Conversation Invite他们一次但是请记住就是在他们Left之前把退出的用户记录下来要不然你不知道该重新邀请谁还有千万别忘记在ContactJoin之前把要发送的消息缓沖join之后才能发送 最后加一句所有的示例代码都可以在MSNPSharp的那个Example客户端看到 //本代码取自 MSNPSharpExampleClientConversationFormcs privatevoidSwitchboard_ContactJoined(objectsenderContactEventArgse) { if(conversationTextBoxInvokeRequired) { Delegate_Switchboard_ContactJoinedd=newDelegate_Switchboard_ContactJoined(Switchboard_ContactJoined); object[]args={}; args[]=sender; args[]=e; conversationTextBoxInvoke(dargs);//线程切换 } else { conversationTextBoxText+=*+eContactName+joinedtheconversation\r\n; _contactStatus[eContactMailToLowerInvariant()]=true; //Sendallmessagesandnudges if(_messagequeneCount>) { for(inti=;i<_messagequeneCount;i++) { _conversationSwitchboardSendTextMessage(_messagequene[i]);//把之前缓沖的消息发送出去 } _messagequeneClear(); } if(_nudgequeneCount>) { foreach(objectobin_nudgequene) { _conversationSwitchboardSendNudge();//把之前缓沖的闪屏发送出去 } _nudgequeneClear(); } } } privatevoidSwitchboard_ContactLeft(objectsenderContactEventArgse) { if(conversationTextBoxInvokeRequired) { conversationTextBoxInvoke(newContactChangedEventHandler(Switchboard_ContactLeft) newobject[]{sendere}); } else { conversationTextBoxText+=*+eContactName+lefttheconversation\r\n; if(!_leftusersContains(eContactMail)) _leftusersAdd(eContactMail);//记录下离开的用户 _contactStatus[eContactMailToLowerInvariant()]=false; } } voidSwitchboard_AllContactsLeft(objectsenderEventArgse) { RemoveEvent(); ConversationSwitchboardClose();//所有的用户都离开了关闭Conversation }
//发送消息 privatevoidSendInput() { //checkwhetherthereisinput if(inputTextBoxTextLength==)return;//不能发送空消息 TextMessagemessage=newTextMessage(inputTextBoxText); _typingMessageSended=false; inputTextBoxText=StringEmpty; conversationTextBoxText+=Yousay:+messageText+\r\n; //Allcontactsleftrecreatetheconversation if(ReInvite())//如果对方已经退出会话重新邀请 { _messagequeneAdd(message);//缓沖消息暂不发送 return; } ConversationSwitchboardSendTextMessage(message);//发送消息 }
//重新邀请 privateboolReInvite() { if(!ConversationSwitchboardIsSessionEstablished)//如果发现Session已经断开(Conversation已经关闭) { _clientformDicconversationRemove(_conversation); RemoveEvent(); _conversation=_conversationMessengerCreateConversation();//重新简历Conversation _clientformDicconversationAdd(_conversationthis); AddEvent(); foreach(stringaccountin_leftusers) { _conversationInvite(account);//邀请退出了的用户 } _leftusersClear(); returntrue; } returnfalse; } |