基于UDP的通信模块

(整期优先)网络出版时间:2010-05-15
/ 3

基于UDP的通信模块

高浩1,杨光2

高浩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平台