高浩1,杨光2
(中山大学,广东广州510006)
摘要:程序间的通信是一个老生常谈的话题了,不论是聊天程序、还是文件传输程序,都离不开数据的传递。而现在,编写一个数据传输的程序也并不是什么难事。但是,许多程序员每次在编写一个新程序时,都在从零开始编写程序间的通信部分,这就让我们把大量时间浪费在重复劳动上。所以很有必要把我们已经做好的通信部分模块化,这样,以后再编写相关部分时,只需把以前编好模块应用到新的程序中即可。
关键词:UDP;模块化;C#;通信
中图分类号:TP393.07文献标识码:A文章编号:1007-9599(2010)05-0000-02
CommunicationModuleBasedonUDP
GaoHao,YangGuang
(SunYat-senUniversity,Guangzhou510006,China)
Abstract:Thecommunicationbetweentheprogramisacommonplacesubject,eitherchatprogram,orfiletransferprocedure,isinseparablefromthedatatransfer.Andnow,writeadatatransferprogramisnotsodifficultHowever,whenprogrammerswritinganewprogram,theyoftencodethecommunicationmodulesfromscratch.Thesemakeuswastetimeonrepeatedlabor.Soitisverynecessarytomodularizethecommunicationpart.Whenwecodetherelevantparts,wecanjustapplythemoduletothenewprogram.
Keyword:UDP;Modularization;C#;Comunication
一、概述:
接下来,将编写一个采用UDP协议的通信模块,它负责接受、发送和处理数据。它采用模块化的设计思想,可以处理诸如消息传送、文件传送等事务。
二、UDP模块的具体实现代码:
publicpartialclassUDPSocket:Component
{
privateintlocalPort=11000;
privateIPEndPointServerEndPoint=null;//定义网络端点
privateUdpClientUDP_Server=newUdpClient();//创建网络服务,也就是UDPSocket
privateSystem.Threading.ThreadthdUdp;//创建一个线程
publicdelegatevoidDataArrivalEventHandler(byte[]Data,IPAddressIp,
intPort);
publiceventDataArrivalEventHandlerDataArrival;//在控件中定义一个事件
privatestringlocalHost="127.0.0.1";
privateboolactive=false;
publicboolActive
{
get{returnactive;}
set
{active=value;
if(active)
OpenSocket();
else
CloseSocket();
}
protectedvoidListener()
{
ServerEndPoint=newIPEndPoint(IPAddress.Any,localPort);
if(UDP_Server!=null)
UDP_Server.Close();
UDP_Server=newUdpClient(localPort);//创建一个新的端口号
UDP_Server.Client.ReceiveBufferSize=1000000000;//接收缓冲区大小
UDP_Server.Client.SendBufferSize=1000000000;//发送缓冲区大小
thdUdp=newThread(newThreadStart(GetUDPData));
thdUdp.IsBackground=true;
thdUdp.Start();
}
privatevoidGetUDPData()/
{
while(active)
{
//将获取的远程消息转换成二进制流
byte[]Data=UDP_Server.Receive(refServerEndPoint);
if(DataArrival!=null){
//利用当前控件的DataArrival事件将消息发给远程计算机
DataArrival(Data,ServerEndPoint.Address,ServerEndPoint.Port);
Thread.Sleep(50);
}
}
}
publicvoidSend(System.Net.IPAddressHost,intPort,byte[]Data)
{
IPEndPointserver=newIPEndPoint(Host,Port);
UDP_Server.Send(Data,Data.Length,server);
}
privatevoidOpenSocket()
{
Listener();
}
privatevoidCloseSocket()
{
if(UDP_Server!=null)
UDP_Server.Close();
if(thdUdp!=null)//如果自定义线程被打开
{
Thread.Sleep(30);//睡眠主线程
thdUdp.Abort();//关闭子线程
}
}
}
这样,一个基于UDP的通信模块就基本实现了,但是它还不具备任何实际的功能,既不能传送消息,也不能传送任何数据。接下来将为它实现简单的文件传输功能来说明它的使用方法。
三、简单文件传输功能的实现
该示例程序采用C/S架构设计。客户端和服务器端各采用一个UDPSocket来处理通讯方面的需求。DataArrival事件将负责处理客户端和服务器端的业务逻辑。当UDPSocket接收到数据时,将引发DataArrival事件,从而引发客户端和服务器端进行不同的处理。
服务器端代码:
privatedelegatevoidDataArrivaldelegate(byte[]Data,System.Net.IPAddressIp,intPort);
privatevoidudpSocket1_DataArrival(byte[]Data,System.Net.IPAddressIp,intPort)
{
DataArrivaldelegateoutdelegate=newDataArrivaldelegate(DataArrival);
this.BeginInvoke(outdelegate,newobject[]{Data,Ip,Port});
}
privatevoidDataArrival(byte[]Data,System.Net.IPAddressIp,intPort)
{
udpSocket1.Send(Ip,Port,Data);
}
客户端代码:
接收文件
privatevoidDataArrival(byte[]Data,System.Net.IPAddressIp,intPort)
{
ClassMsgmsg=newClassSerializer().DeSerializeBinary((newSystem.IO.MemoryStream(Data)))asClassMsg;
FileStreamfileStream=null;
try
{
stringfilePath=Environment.CurrentDirectory+"\\"+msg.FileName;
if(File.Exists(filePath))
filePath=Environment.CurrentDirectory+"\\"+msg.msgID+msg.FileName;
fileStream=newFileStream(filePath,FileMode.Create);
fileStream.Write(msg.Data,0,msg.Data.Length);
}
finally
{
fileStream.Close();
}
}
发送文件
privatevoidtsSendFile_Click(objectsender,EventArgse)
{
if(openFileDialog1.ShowDialog()==DialogResult.OK)
{
IPAddressip=IPAddress.Parse(Publec_Class.ServerIP);
stringport=Publec_Class.ServerPort;
FileStreamfileStream=newFileStream(openFileDialog1.FileName,FileMode.Open,FileAccess.Read);
MemoryStreammemStream=newMemoryStream();
intb=fileStream.ReadByte();
while(b!=-1)
{
memStream.WriteByte((byte)b);
b=fileStream.ReadByte();
}
byte[]data=memStream.ToArray();
ClassMsgmsg=newClassMsg();
msg.Data=data;
msg.msgID=Guid.NewGuid().ToString();
msg.FileName=openFileDialog1.SafeFileName;
udpsocket.Send(ip,Convert.ToInt32(port),
newClassSerializer().SerializeBinary(msg).ToArray());
}
}
这样,一个简单的文件传输功能就完成了,虽然这个示例里面没有把传输文件的大小等因素考虑在内,但是,作为一个示例来说,也足够清晰了。当然,我们也可以对这个示例进行进一步的扩充以实现更为强大功能。
四、总结
编写比较大型的软件时,直接从头开始开发耗费人力物力。通过重用以前的代码,可以快速高效的开发程序。而为了进行代码的重用,我们需要在编写程序时注意对软件进行模块化。每个模块应该是自治的,它隐藏具体的实现,只提供程序的接口。这样有利于对错误的排查、软件的维护和升级。
本文通过一个UDP通信模块的示例程序,展示了模块化编程的优点。之后通过一个示例程序,演示了该模块的用法。但是此模块的应用并不仅仅局限于此,它还能用于大部分的数据传输任务,这一切将有待于读者去发掘。
作者简介:
高浩(1990-),男,山东省巨野县人,单位全称:中山大学,学历:本科在读,研究方向:.net平台
杨光(1990-),男,山东省聊城市人,单位全称:中山大学学历:本科在读,研究方向:.net平台