版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
基于TCP协议的网络通信系统的设计与实现摘要:网络通信,由于其具有实时性、跨平台性、本钱低、效率高等优点而受到广泛的使用。设计并实现一个能够处理多用户进行实时、平安的即时通信系统具有较强的现实意义。即时通信的底层通信是通过SOCKET套接字接口实现的。当前的主流UNIX系统和微软的WINDOWS系统都在内核提供了对SOCKET字接口的支持。使用这个统一的接口,可以编写一个可移植的TCP/IP通信程序。使信息能够在INTERNET上可靠的传输。本文设计并实现了基于局域网内的简单即时通信系统,系统采用C/S模式,底层通信通过SOCKET套接字接口实现,效劳器负责客户端的登录验证,好友信息的保存和心跳报文的发送。客户端采用P2P方式实现消息传递,并能实现文件的传输。本文首先讨论了同步套接字,异步套接字,多线程并发执行任务等;然后阐述了客户端、效劳器如何使用XML序列化的消息进行通信。关键词:即时通信;文件传输;套接字;TCP协议Abstract:Instantmessageshaveseveraladvantagessuchasreal-time,cross-platform,cheapandefficient.TodesignaMulti-userIM(instantmessage)architectureisveryimportantinboththeoryandrealism.InstantmessagebasedonTCP/IPprotocolthatisrealizedbysocketinterface.AlmostallUNIXoperationsystemsandMicrosoft'swindowsoperationsystemsprovidesupportofsocketinthekernel.Usingtheuniforminterface,wecandevelopaportableprogramofTCP/IP,whichhelpustransferinformationinInternetsafelyandcredibly.Thesystemusestheclient/server(C/S)mode.Theservertakestheresponsibilityoftheloginmessageofclient,thesavingoffriendmessageandMessageheartbeat.ThetransmissionofthebasicmessagesofthecustomerendwillbedesignedonP2Parchitecture.ThisthesisexplainshowtheclientandservercommunicateviaserializingXMLmessage.Keywords:InstantMessage;FileTransfer;Socket;TCPprotocol引言1.1课题背景即时通信是一个终端连往一个即时通信网路的效劳。即时通信不同于e-mail在于它的交谈是实时的。大局部的即时通信效劳提供了presenceawareness的特性──显示联络人名单,联络人是否在在线与能否与联络人交谈。最早的即时通信软件是ICQ,ICQ是英文中Iseekyou的谐音,意思是我找你。四名以色列青年于1996年7月成立Mirabilis公司,并在11月份发布了最初的ICQ版本,在六个月内有85万用户注册使用。在因特网上受欢送的即时通信效劳包含了MSNMessenger、AOLInstantMessenger、Yahoo!Messenger、NETMessengerService、Jabber、ICQ与QQ。这些效劳有赖于许多想法更久的(与普遍)的在线聊天媒介,如InternetRelayChat一样知名。1970年代早期,一种更早的即时通信形式是柏拉图系统(PLATOsystem)。之后在1980年代,UNIX/Linux的交谈实时信息被广泛的使用于工程师与学术界,1990年代即时通信更跨越了因特网交流。1996年11月,ICQ是首个广泛被非UNIX/Linux使用者用于因特网的即时通信软件。在ICQ的介绍之后,同时在许多地方有一定数量的即时通信方式开展,且各式的即时通信程序有独立的协议,无法彼此互通。这引导使用者同时执行两个以上的即时通信软件,或者他们可以使用支持多协议的终端软件,如Gaim、Trillian或Jabber。1.2国内外研究现状国外研究现状当今,国际上对网络通信系统研究的较好的公司有,思科,Sun,Ms等公司,思科主要研究的是底层的传输;MS,Sun公司研究的是应用层。其中ms公司凭借其在操作系统的垄断地位,为了在网络的开展中取得先机,采用了各种各样的手段。但是,其捆绑的msn,无论从功能上,还是技术上来说,都不算是非常先进的。当然,ie,同样也不是很受人青睐,这让人想起了,当年的网景公司,网景只是生不逢时。MS不择手段的想打跨网景,可见其对网络的重视。如今,Sun公司在网络应用上捷足先登,凭借着Java,Sun在网络的应用上领先于MS。微软,想用同样的方法搞跨对手,因此它拿出了Visualc#,来对抗Java。这些都是在应用层面的开发工具。应用层上的产品就更显种类繁多。ICQ几乎是国际上通用的即时通信工具,由于在我国它的应用不是很广,所以,其原理也很少被介绍。msn,是MS的产品,同样在国内没什么市场,所以,对其原理,也很少被讨论过。至于ie,是在Visualc++下开发的产品,虽然有严重的平安隐患,不过,至少能在某种程度上代表当今国际研究的水平。此外,国际上最近出先了新的浏览器Firefox,其性能据说是远高于ie,也许在网络的天下,Ms又有了更强劲的对手。国内研究现状国内在应用层上的网络应用软件目前开展异常的火爆,因为我国有着网络应用的最大的市场,现在国内网络的根底性建设开展迅速,应用软件也层出不穷,其中,在游戏的领域中,网络通信的工作做的不错,如联众游戏平台,还有其他的一些平台,这些平台根本上都是基于VC++的,用的都是Socket通信,但是为了效率,这些平台没有用MFC提供的CSocket类,而是直接用Socket进行通信。所以效率上不错。此外,tencent的即时通信,也是做的很好的,从某中程度上来说,代表了国内最高的水平。1.3本课题的研究方法本系统采用C/S〔Client/Server〕结构进行设计,使用SQLServer2000构建数据库,并在.NET环境下使用VisualC#.net语言和SOCKET套接字开发一个基于TCP协议的简单即时通信软件,实现简单的即时聊天,文件传输等功能。2相关技术介绍2.1.NET开发平台及C#.NET开发语言NET框架是Microsoft公司推出的一种全新的开发平台,提供了统一的、面向对象并且可以扩展的编程类库和完善的集成开发环境,大大简化了应用程序的开发过程,并且具有良好的移植性和平安性。微软为了推行.NET战略,特别为.NET平台设计了一种语言——C#。C#是由C和C++派生而来的一种“简单、流行、面向对象、类型平安〞的程序设计语言,其综合了Visualbasic的高效率和C++的强大功能,然而更多的人感觉C#更类似JAVA。2.2TCP协议TCP/IP网络协议协议是对等的网络实体之间通信的规那么,可以简单地理解为网络上各计算机彼此交流的一种“语言〞。网络通信协议设计的根本原那么是层次化,层和协议的集合被称为网络体系结构。相邻层之间的接口定义了下层向上层提供的根本操作和效劳,下层向上层提供的效劳分两种形式:面向连接的效劳和无连接的效劳。计算机网络中已经形成的网络体系结构主要有两个:OSI参考模型和TCP/IP参考模型。TCP/IP参考模型是因特网〔Internet〕的根底。和OSI的7层协议相比,TCP/IP协议只有4个层次。通常说的TCP/IP是一组协议的总称,TCP/IP实际上是一个协议族,包括100多个相互关联的协议,其中IP(InternetProtocol,网际协议)是网络层最主要的协议;TCP(TransmissionControlProtocol,传输控制协议)和UDP(UserDatagramProtocol,用户数据报协议是传输层中最主要的协议),一般认为IP、TCP、UDP是最根本的三种协议,是其他协议的根底。TCP——传输控制协议:面向连接的通信可以使用可靠通信,在这时候,第四层协议发送数据接收方确实认,如果未收到数据或者数据被损坏,那么请求重新传输。TCP协议就使用这种可靠通信。使用TCP协议的应用层协议包括HTTP、FTP、SMTP和Telnet等。现在可以发送和接收消息了。接收消息后,总是返回ACK消息。如果在收到ACK之前发送方已经超时,那么消息将被放到重发队列中以再次发送。由于它的握制,所以TCP协议比拟复杂并且费时,但此协议在处理数据时对数据包的传送有保障,从而使得在应用程序协议中不需要再包括该功能。2.3套接字套接字这个术语并没有定义某个协议:它具有两层含义,但两者都与一个协议相关。第一个含义是套接字编程API,它最初由伯克利大学为BSDUNIX而创立。BSD套接字在经过修改后被用作Windows环境的编程接口〔并且被命名为WinSock〕。WinSockAPI被包装在System.Net.sockets命名空间的.NET类中。WindowsSockets是一个独立于协议的编程接口,用于编写网络应用程序。2.4流流的根本概念流的概念已经存在很长时间了。流是一个用于传输数据的对象。数据的传输有两个方向:1)如果数据从外部源传输到程序中,这就是读取流。2)如果数据从程序传输到外部源,这就是写入流。外部源常常是一个文件,但也不完全都是文件,它还可以是:1)网络,使用一定的网络协议与网络上其它计算机或终端交换数据。2〕一个指定的管道。3)一块内存区域。2.5同步、异步、阻塞和非阻塞同步〔synchronous〕:所谓同步方式,就是发送方发送数据包以后,不等接受方响应,就接着发送下一个数据包。异步〔asynchronous〕:异步方式就是当发送方发送一个数据包以后,一直等到接受方响应后,才接着发送下一个数据包。阻塞〔Block〕:指执行此套接字的网络调用时,直到调用成功才返回,否那么此套节字就一直阻塞在网络调用上,比方调用StreamReader类的Readlin()方法读取网络缓冲区中的数据,如果调用的时候没有数据到达,那么此Readlin()方法将一直挂在调用上,直到读到一些数据,此函数调用才返回。非阻塞〔Unblock〕:指在执行此套接字的网络调用时,不管是否执行成功,都立即返回。同样调用StreamReader类的Readlin()方法读取网络缓冲区中数据,不管是否读到数据都立即返回,而不会一直挂在此函数调用上。在Windows网络通信软件开发中,最为常用的方法就是异步非阻塞套接字。平常所说的C/S〔客户端/效劳器〕结构的软件采用的方式就是异步非阻塞模式的。其实在用C#进行网络编程中,我们并不需要了解什么同步、异步、阻塞和非阻塞的原理和工作机制,因为在.NetFrameWrokSDK中已经已经把这些机制给封装好了。3.系统总体设计3.1需求分析软件针对局域网内部用户,实现用户间的即时通信。需要分别实现效劳器端和客户端的软件设计。效劳器端负责监听用户连接请求,负责连接数据库存储用户信息,负责发送给用户好友信息,负责发送心跳报文检查用户在线状态并即时让用户更新好友在新信息。客户端发起主动连接,向效劳器请求登录或者注册。客户端可以修改昵称,可以加用户为好友〔类似于MSN的好友添加功能〕。客户端之间可以发起P2P模式的聊天,可以传送文件。3.2系统根本架构基于C/S架构的即时通信软件便于对用户信息进行统一管理和保存,面向特定的用户,对信息的平安控制能力很强。为了减轻效劳器负担,客户端之间的信息传递是采用P2P模式的,效劳器只负责用户的注册,登录和用户在线状态的检验。根本结构如图:3.3功能模块设计CLIENT:1.注册:(1)可以完成客户端注册,客户端可以通过填写信息进行注册,信息被发送到效劳器端。2.登录:(1)客户可以输入账号和密码进行登录,客户端会发送登录信息等待效劳器响应,登录成功后会发出登录成功信息并刷新好友列表。3.修改:(1)密码修改:应该有密码修改功能(2)信息修改:可以更改一些注册信息4.通信:(1)即时聊天模块:客户端与客户端之间建立线程进行即时聊天,也包含有简单的对称加解密算法功能。(2)好友列表:可以对好友列表进行添加删除等动作。5.文件传输:(1)文件传输:文件传输功能SERVER:注册回应:对客户端传送的注册信息进行判断。(1)HASH加密:对用户的账号和密码信息进行HASH加密(2)重复用户检查:将加密后信息与已存在账号进行比拟,检查是否账号已存在,如果存在就返回错误信息〔3)注册成功:将可成功注册的用户账号和密码写入数据库内,并向客户端返回成功信息2.修改回应:(1)对密码和信息修改请求进行判断,执行和返回修改成功信息。3.登录回应:(1)对登录的账号和密码进行加密检查后发回正确或错误情况,并记录上线信息。(2)好友列表发送:给成功登录的账号发送好友列表及好友上线信息。(3)上线信息发送:给成功登录的账号的好友发送在线信息〔包括IP,端口等等信息〕。4.在线情况:(1)对登录,在线,离线的用户情况进行统计,记录和通知(2)心跳测试:每隔一段时间发送报文测试用户是否因意外原因离线(3)情况记录:将用户登录时间,IP,下线时间等信息记录入数据库3.4逻辑图:3.5数据库设计实体关系图效劳器是作为记录和读取数据库信息的载体,与客户端关系并不复杂,这里需要重点考虑客户端之间的关系。用户与用户之间的关系是较为特殊的递归关系,即描述发生在两个相同实体上的关系。4系统实现4.1使用XML定义的即时通信协议信息结构MESSAGE.CS&UMESSAGE.CS这两个C#类定义了包括效劳器信息,状态信息,注册信息,登录信息,聊天信息或者请求文件传输信息的函数,效劳器和客户端通过将它们实例化和序列化再转换成流在网络上进行传输。UMESSAGE.CS主要代码如下:[Serializable]publicclassUMessage{publicUMessage(){}privatestring_nickname;privatestring_password;privatestring_accounts;privatestring_email;privateint_info;//表示注册或者登录信息,客户端信息0为注册,1为登录;效劳器返回信息0为用户已存在,1为注册成功,2为效劳器未知错误,3为CLIENT在线检查,10为登录失败,11为登录成功privateFriend[]_friend;privateint_fn;privatestring_fg;publicstringNickname{get{return_nickname;}set{_nickname=value;}}publicstringPassword{get{return_password;}set{_password=value;}}publicstringAccounts{get{return_accounts;}set{_accounts=value;}}publicstringEmail{get{return_email;}set{_email=value;}}publicintInfo{get{return_info;}set{_info=value;}}publicFriend[]Fri{get{return_friend;}set{_friend=value;}}publicintFn{get{return_fn;}set{_fn=value;}}publicstringFg{get{return_fg;}set{_fg=value;}}}由于MESSAGE.CS与UMESSAGE.CS类似,在此不再详述。效劳器和客户端都可以通过相同的代码对UMESSAGE赋值,再通过XmlSerializer方法进行将UMESSAGE序列化为XML文档,最后将XML文档转化为网络流进行传输。代码如下:#region将登录信息转为UMessageprivatevoidTraslator(){_message.Accounts=this.TextBox1.Text;_message.Nickname="";_message.Password=this.TextBox2.Text;_message.Email="";_message.Info=1;_message.Fri=null;}#endregion数据结构FriendStruct效劳器如果保存和传递用户的好友信息是难点之一。数据库的设计和信息的传递区分都是比拟难实现的。在数据库方面,每个用户拥有各自的好友分组信息〔UserFav〕,分组中间使用“,〞分隔,在TCP_FriendInfo表中那么分别保存了用户ID和好友ID,使用一个INT字段保存分组信息。数据库以用户ID为标准对好友ID和分组信息进行内连接查询,就可以得到根本的好友信息了。代码如下:select*fromTCP_UserInfojoinTCP_FriendInfoonTCP_FriendInfo.UserID='"+uid+"'andTCP_UserInfo.UserID=TCP_FriendInfo.FriendID在好友信息的传输方面,首先定义一个FriendStruct数据结构〔当然也可以用枚举完成〕如下:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceTCP{publicclassFriendStruct{publicstructFileInfo{publicintfilere;//接收和拒绝信息,1为接收,2为拒绝,3为取消publicstringfilename;publiclongfilelength;}}publicstructFriend{publicstringaccount;publicstringnickname;publicstringIP;publicstringstatus;publicstringfg;//好友分组}}在MESSAGE.CS或者UMESSAGE.CS中,我们那么定义了FriendStruct的数组。在C#中使用DATAREADER语句可以逐句读取数据库查询的结果,再依次将结果赋值FriendStruct数组元素,就得到了便于发送和读取的存放好友信息的数组。赋值代码如下:while(getf.Read())//getf即是以上的数据库查询的datareader语句{ff[i].account=getf["UserAccount"].ToString();ff[i].IP=getf["UserIP"].ToString();ff[i].nickname=getf["UserNickname"].ToString();ff[i].status=getf["UserOnline"].ToString();ff[i].fg=getf["FriendGroup"].ToString();i++;}getf.Close();4.2数据库连接类实现一个快捷简单的数据库连接的相关代码是非常有必要的。实现的途径也多种多样,鉴于平安性和复杂性的需求不同,实现方法有简有繁。本设计使用了一个简单的类〔UserData.CS〕实现了简单快捷的数据库连接和读取。主要代码如下:publicstaticSqlConnectionconnStr=newSqlConnection("Server=D96B85DD938A465.;uid=sa;pwd=change;database=TCPDB");publicstaticSqlDataReaderSqlReader(stringsql,SqlConnectionconnstr){SqlDataReadersqldr=null;SqlCommandcmd=newSqlCommand(sql,connstr);if(cmd.Connection.State.ToString()=="Closed")cmd.Connection.Open();try{sqldr=cmd.ExecuteReader();}catch(Exceptione){catch(Exceptione){if(e!=null)sqldr=null;}returnsqldr;}//数据库操作连接publicstaticstringSqlCmd(stringsql,SqlConnectionconnstr){stringerrorstr=null;SqlCommandsqlcmd=newSqlCommand(sql,connstr);if(sqlcmd.Connection.State.ToString()=="Open")sqlcmd.Connection.Close();sqlcmd.Connection.Open();try{sqlcmd.ExecuteNonQuery();}catch(Exceptione){if(e!=null)errorstr=e.ToString();}sqlcmd.Connection.Close();returnerrorstr;}在UserData.CS的根底上,主程序可以更方便地实现数据库连接操作,对数据库进行读写和更新,在此不再详述。4.3效劳器端效劳器端的界面设计是基于便于测试的目的而实现的。如下列图:同步套接字网络监听基于同步套接字的网络监听器对效劳器来说并不是最好的解决方案,但是仍然可行并且实现简单。主要代码如下:开启监听端口:publicvoidServe(){intport=8888;ServerIPEP=newIPEndPoint(IPAddress.Any,port);s=newSocket(ServerIPEP.AddressFamily,SocketType.Stream,ProtocolType.Tcp);s.Bind((EndPoint)ServerIPEP);s.Listen(10);alSock=newArrayList();以下代码读取连入的连接,依次将连接参加可变长数组alsock,并且读取传入的信息,进行反串行化:while(true){try{uc=s.Accept();alSock.Add(uc);this.tb_states.AppendText(System.Convert.ToString(uc));byte[]data=newbyte[2048];intrect=uc.Receive(data);byte[]chat=newbyte[rect];Buffer.BlockCopy(data,0,chat,0,rect);UMessageumessage=(UMessage)_translator.Deserialize(newMemoryStream(chat));intinfo=umessage.Info;对反串行化后的信息进行处理,通过info参数识别客户端行为〔注册或者登录〕,对注册的信息进行数据库查询,注册信息可插入,那么将用户信息插入数据库,否那么返回客户端“注册出错〞的信息:#region处理用户注册信息if(info==0)//分辨出用户发送的是注册信息{stringAccounts=umessage.Accounts;SqlDataReaderusdr=FPara.SqlReader("select*fromTCP_UserInfowhereUserAccount='"+Accounts+"'",FPara.connStr);if(usdr!=null){if(usdr.Read()){#region此处写入返回注册失败的代码Socketsc=(Socket)alSock[alSock.IndexOf(uc,0)];sc.Send(chat);#endregion}else{#region此处写入插入数据库用户注册信息的代码Streamms=newMemoryStream();Socketsc=(Socket)alSock[alSock.IndexOf(uc,0)];if(FPara.SqlCmd("insertintoTCP_UserInfo(UserAccount,UserNickname,UserEmail,JoinDate,UserIP,UserPassword)values('"+umessage.Accounts+"','"+umessage.Nickname+"','"+umessage.Email+"','"+System.DateTime.Now.ToString()+"','"+((IPEndPoint)uc.RemoteEndPoint).Address.ToString()+"','"+umessage.Password+"')",FPara.connStr)==null){umessage.Info=1;_translator.Serialize(ms,umessage);byte[]d=newbyte[ms.Length];ms.Seek(0,SeekOrigin.Begin);ms.Read(d,0,d.Length);sc.Send(d);}else{umessage.Info=2;_translator.Serialize(ms,umessage);byte[]d=newbyte[ms.Length];ms.Seek(0,SeekOrigin.Begin);ms.Read(d,0,d.Length);sc.Send(d);}#endregion}usdr.Close();}}#endregion如果发现用户发送的是登录信息,就根据登录信息中的用户名和密码判断是否存在用户,密码是否正确,成功后再查询出用户的好友信息并且赋值给FriendStruct,再将信息返回给客户端:#region处理用户登录信息elseif(info==1)//分辨出用户发送的是登录信息stringAccounts=umessage.Accounts;stringPassword=umessage.Password;SqlDataReaderusdr=FPara.SqlReader("select*fromTCP_UserInfowhereUserAccount='"+Accounts+"'andUserPassword='"+Password+"'",FPara.connStr);if(usdr!=null){if(usdr.Read()){stringuid=usdr["UserID"].ToString();umessage.Fg=usdr["UserFav"].ToString();usdr.Close();SqlDataAdaptersdr=newSqlDataAdapter("select*fromTCP_UserInfojoinTCP_FriendInfoonTCP_FriendInfo.UserID='"+uid+"'andTCP_UserInfo.UserID=TCP_FriendInfo.FriendID",FPara.connStr);DataSetds=newDataSet();sdr.Fill(ds,"find");intxxx=ds.Tables["find"].Rows.Count;FPara.SqlCmd("updateTCP_UserInfosetUserIP='"+((IPEndPoint)uc.RemoteEndPoint).Address.ToString()+"',UserOnline=1whereUserAccount='"+Accounts+"'",FPara.connStr);ff=newFriend[xxx];inti=0;SqlDataReadergetf=FPara.SqlReader("select*fromTCP_UserInfojoinTCP_FriendInfoonTCP_FriendInfo.UserID='"+uid+"'andTCP_UserInfo.UserID=TCP_FriendInfo.FriendID",FPara.connStr);while(getf.Read()){ff[i].account=getf["UserAccount"].ToString();ff[i].IP=getf["UserIP"].ToString();ff[i].nickname=getf["UserNickname"].ToString();ff[i].status=getf["UserOnline"].ToString();ff[i].fg=getf["FriendGroup"].ToString();i++;}getf.Close();#region此处写入登录成功代码Streamms=newMemoryStream();Socketsc=(Socket)alSock[alSock.IndexOf(uc,0)];this.lb_users.Items.Add(alSock.IndexOf(uc).ToString());umessage.Info=11;umessage.Fri=ff;umessage.Fn=xxx;_translator.Serialize(ms,umessage);byte[]d=newbyte[ms.Length];ms.Seek(0,SeekOrigin.Begin);ms.Read(d,0,d.Length);sc.Send(d);//在tb_status中写入效劳器返回给客户端的代码便于测试观察this.tb_states.AppendText(System.Text.Encoding.Default.GetString(d));#endregion}else{usdr.Close();#region此处写入登录失败代码Streamms=newMemoryStream();Socketsc=(Socket)alSock[alSock.IndexOf(uc,0)];umessage.Info=10;_translator.Serialize(ms,umessage);byte[]d=newbyte[ms.Length];ms.Seek(0,SeekOrigin.Begin);ms.Read(d,0,d.Length);sc.Send(d);#endregion}}}#endregionTb_states是个用于监视SOCKET传入信息的文本框,便于观察和测试相关信息:this.tb_states.AppendText("["+uc.RemoteEndPoint.ToString()+"]"+System.Text.Encoding.Default.GetString(chat));}catch(Exceptionex){MessageBox.Show(ex.Message);}}}以上代码也包含了对客户端的请求信息的判断和对客户端返回信息的生成和传输。多线程对于效劳器来说,多线程是必不可少的,否那么它将无法处理不断请求的新连接。C#的System.Threading提供了多线程编程的支持。本设计实现代码如下:this.th=newThread(newThreadStart(Serve));//新建一个用于监听的线程th.Start();//翻开新线程不仅仅是效劳器,基于P2P模式聊天的客户端也必须支持多线程运行,实现代码与之类似,在客户端设计说明中将不再表达。计时器计时器用于实现心跳报文的功能,效劳器在启动以后就开始计时,每隔一定时间就向所有连入的客户端发送信息,核心代码如下://用计时器检查客户端是否掉线aTimer=newSystem.Timers.Timer();aTimer.Elapsed+=newElapsedEventHandler(CheckStatus);//设置引发时间的时间间隔此处设置为5秒〔5000毫秒〕aTimer.Interval=5000;aTimer.Enabled=true;CheckStatus就是用于向客户端发送检查信息的方法,它会向遍历连入的客户端(alSock),然后依次向客户端发送信息,如果发现客户端没有响应,就会如果发现对方无回应,那么关闭相应的SOCKET,并更新数据库的用户在线状态,同时向该用户的所有好友发送用户已下线的通知。4.4客户端4.4客户端图5注册界面图6登录、聊天、文件传输界面同步套接字客户端客户端发起同步套接字连接,并传送登录或者注册信息,由于两者方式类似,这里仅列出用户登录的代码:#region发送效劳器登录信息,并接收效劳器反应信息publicvoidClient(){建立SOCKET发送信息:try{IPEndPointServerIPEP=newIPEndPoint(IPAddress.Parse("6"),8888);c=newSocket(ServerIPEP.AddressFamily,SocketType.Stream,ProtocolType.Tcp);c.Connect((EndPoint)ServerIPEP);s=newMemoryStream();_translator.Serialize(s,_message);byte[]d=newbyte[s.Length];s.Seek(0,SeekOrigin.Begin);s.Read(d,0,d.Length);inti=c.Send(d,0,d.Length,SocketFlags.None);}catch(Exceptionex){MessageBox.Show(ex.Message);}以下代码读取了效劳器返回给客户端的信息〔注册和登录的成功与失败〕,如果返回了登录成功的信息,还会读取效劳器给出的FriendStruct结构以得到用户的好友信息:#region接收反应信息byte[]data=newbyte[2048];while(true){intrect=c.Receive(data);byte[]chat=newbyte[rect];Buffer.BlockCopy(data,0,chat,0,rect);UMessagebumessage=(UMessage)_translator.Deserialize(newMemoryStream(chat));string[]fg;string_fg=bumessage.Fg;if(bumessage.Info==3){}elseif(bumessage.Info==11){fg=_fg.Split(',');intxxx=bumessage.Fn;ff=bumessage.Fri;for(inti=0;i<xxx;i++){string[]ems=newstring[5];ems[0]=ff[i].account;ems[1]=ff[i].nickname;ems[2]=fg[int.Parse(ff[i].fg)];ems[3]=ff[i].IP;ems[4]=ff[i].status;ListViewItemitem=newListViewItem(ems);this.listView1.Items.Add(item);}CSERVER是一个用于开启监听P2P信息的方法,客户端在登录成功以后就会立刻开启监听器,才能够实现与其它客户端的聊天:Th=newThread(newThreadStart(CServer));//新建一个用于监听其它客户端信息的线程th.Start();//翻开新线程MessageBox.Show(bumessage.Accounts+"登录成功!");this.Button1.Enabled=false;this.Button3.Enabled=false;}elseif(bumessage.Info==2){MessageBox.Show("效劳器未知错误");}else{MessageBox.Show(bumessage.Info.ToString());}}#endregion}#endregion客户端之间的聊天同样使用了序列化的XML文档,用户在登录成功后就会启动一个新的监听器去监听其它客户端传入的聊天信息并且进行判断再将其它用户的聊天信息显示在界面上。这里也不再阐述代码。.4.2采用异步套接字的文件传输文件传输是通过一个类库实现的。由于文件传输的代码实现复杂,通过类库可以大量的简化代码,使主程序简洁易懂。类库Infinity.Networking包括了ClientBase.cs,ClientInfo.cs,Delegates.cs,INPClient.cs,INPServer.cs,ClientBase.cs定义了根底的文件发送函数,INPClient.cs那么仅包含初始化文件发送的函数;ServerBase.cs和INPServer.cs那么是反之亦然。核心代码如下:ClientBase.cs:这个类实现了套接字的开启和数据的传输ClientBase.cs:这个类实现了套接字的开启和数据的传输usingSystem;usingSystem.Net;usingSystem.Net.Sockets;namespaceInfinity.Networking{///<summary>///ClientBase摘要.///</summary>publicclassClientBase{privateconstintBUFFERSIZE=4*1024;privateint_port;privatestring_serverIP;privateSocket_mainSoc;privateClientInfo_info;privateAsyncCallback_dataRecievedCallback;//异步回调方法publiceventNetworkEventHandlerDataRecieved;//定义一个事件:接收到数据时引发事件publicClientBase(stringserverIP,intport){_serverIP=serverIP;_port=11000;_mainSoc=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);_info=newClientInfo(_mainSoc,newbyte[BUFFERSIZE]);//ClientInfo包含了建立的套接字和套
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024山西房产买卖合同(含环保材料及节能标准)3篇
- 个人房屋租赁合同
- 设施齐全商铺长期租赁合同
- 2024年中国水性聚酯透明底漆市场调查研究报告
- 2024年度智能仓储管理系统软件变更与物流跟踪服务合同3篇
- 2024至2030年中国宽带混合器行业投资前景及策略咨询研究报告
- 2024版住宅小区车位销售及智能化家居服务协议3篇
- 2024年中国立式浆渣连续分离机市场调查研究报告
- 2024年度高端工地食堂设计与承包服务合同书3篇
- 2024年度林地基站建设租用合同3篇
- S学习问题个性化分析诊断系统v2.0 分析标准
- 因式分解法一元二次方程练习100题及答案
- 楼层板施工栓钉焊接
- 人音版 一年级上册《国旗国旗真美丽》(教案)
- 勘察设计方案进度计划和保障措施
- 增补材料合同范本
- 古琴音乐文化与鉴赏智慧树知到期末考试答案章节答案2024年广东工业大学
- HYT 083-2005 海草床生态监测技术规程(正式版)
- 普通心理学(山东联盟)智慧树知到期末考试答案章节答案2024年滨州医学院
- 运输方案及应急措施(2篇)
- 渗透测试智慧树知到期末考试答案章节答案2024年江苏大学
评论
0/150
提交评论