最近一个项目要用到点对点文件传输,俺就到处找资料写程序,最后终于完成了,为了让别人少走些弯路,俺决定将俺程序中最重要的部分贡献出来,希望对大家有所帮助。
俺的程序分三部分,包括发送部分、接受部分和一个两者共享的通讯基类,这个基类才是俺心血的结晶:)
一、通讯基类
using system;
using system.net.sockets;
using system.net ;
using system.io ;
using system.windows.forms;
using system.text;
namespace baseclass
{
/// <summary>
/// 传送信息的格式为 给定长度的命令部分+给定长度的命令注释部分+可变长度的长度信息+可变长度的信息部分
/// </summary>
public class communclass
{
public communclass()
{
//
// todo: 在此处添加构造函数逻辑
//
}
/// <summary>
/// 命令部分的长度
/// </summary>
private static readonly int cmdlen = 50 ;
/// <summary>
/// 命令注释部分的长度
/// </summary>
private static readonly int desclen = 100 ;
/// <summary>
/// 可变长度的长度信息部分所占的字节数
/// </summary>
private static readonly int dynamiclengthlen = 10 ;
/// <summary>
/// 每次处理可变信息部分的长度
/// </summary>
private static readonly int deallen = 1024 ;
/// <summary>
/// /应答的最大长度
/// </summary>
private static readonly int responlen = 20 ;
/// <summary>
/// 用于填充命令或注释不足长度部分的字符
/// </summary>
private static readonly char fillchar = '^' ;
/// <summary>
/// 成功发送一部分数据后的回调方法(也可以认为是触发的事件,但严格来说还不是)
/// </summary>
public delegate void onsend(int itotal,int isending) ;
/// <summary>
/// 根据给定的服务器和端口号建立连接
/// </summary>
/// <param name="strhost">服务器名</param>
/// <param name="iport">端口号</param>
/// <returns></returns>
public static socket connecttoserver(string strhost,int iport)
{
try
{
ipaddress ipaddress = dns.resolve(strhost).addresslist[0];
ipendpoint ippoint = new ipendpoint(ipaddress,iport) ;
socket s = new socket(addressfamily.internetwork,sockettype.stream,protocoltype.tcp) ;
s.connect(ippoint) ;
return s ;
}
catch (exception e)
{
throw (new exception("建立到服务器的连接出错" + e.message)) ;
}
}
/// <summary>
/// 将文本写到socket中
/// </summary>
/// <param name="s">要发送信息的socket</param>
/// <param name="strinfo">要发送的信息</param>
/// <returns>是否成功</returns>
public static bool writetexttosocket(socket s,string strinfo)
{
byte [] buf = encoding.utf8.getbytes(strinfo) ;
try
{
s.send(buf,0,buf.length,socketflags.none) ;
return true ;
}
catch(exception err)
{
messagebox.show("发送文本失败!"+err.message) ;
return false ;
}
}
/// <summary>
/// 将命令文本写到socket中
/// </summary>
/// <param name="s">要发送命令文本的socket</param>
/// <param name="strinfo">要发送的命令文本</param>
/// <returns>是否成功</returns>
public static bool writecommandtosocket(socket s,string strcmd)
{
if (strcmd == "")
strcmd = "nop" ;
strcmd = strcmd.padright(cmdlen,fillchar) ;
return writetexttosocket(s,strcmd) ;
}
/// <summary>
/// 将命令注释写到socket中
/// </summary>
/// <param name="s">要发送命令注释的socket</param>
/// <param name="strinfo">要发送的命令注释</param>
/// <returns>是否成功</returns>
public static bool writecommanddesctosocket(socket s,string strdesc)
{
if (strdesc == "")
strdesc = "0" ;
strdesc = strdesc.padright(desclen,fillchar) ;
return writetexttosocket(s,strdesc) ;
}
/// <summary>
/// 发送可变信息的字节数
/// </summary>
/// <param name="s">要发送字节数的socket</param>
/// <param name="ilen">字节数</param>
/// <returns>是否成功</returns>
public static bool writedynamiclentosocket(socket s,int ilen)
{
string strlen = ilen.tostring().padright(dynamiclengthlen,fillchar) ;
return writetexttosocket(s,strlen) ;
}
/// <summary>
/// 将缓存的指定部分发送到socket
/// </summary>
/// <param name="s">要发送缓存的socket</param>
/// <param name="buf">要发送的缓存</param>
/// <param name="istart">要发送缓存的起始位置</param>
/// <param name="icount">要发送缓存的字节数</param>
/// <param name="iblock">每次发送的字节说</param>
/// <param name="sendsuccess">每次发送成功后的回调函数</param>
/// <returns>是否发送成功</returns>
public static bool writebuftosocket(socket s,byte [] buf,int istart,int icount,int iblock,onsend sendsuccess)
{
int isended = 0 ;
int isending = 0 ;
while(isended<icount)
{
if (isended + iblock <= icount)
isending = iblock ;
else
isending = icount - isended ;
s.send(buf,istart+isended,isending,socketflags.none) ;
isended += isending ;
if (readresponsionfromsocket(s)=="ok")
if (sendsuccess != null)
sendsuccess(icount,isended) ;
else
return false;
}
return true ;
}
/// <summary>
/// 将长度不固定文本发送到socket
/// </summary>
/// <param name="s">要发送文本的socket</param>
/// <param name="strtext">要发送的文本</param>
/// <param name="onsendtext">成功发送一部分文本后的回调函数</param>
/// <param name="settextlen">得到文本长度的回调函数</param>
/// <returns></returns>
public static bool writedynamictexttosocket(socket s,string strtext,
onsend onsendtext)
{
byte [] buf = encoding.utf8.getbytes(strtext) ;
int ilen = buf.length ;
try
{
writedynamiclentosocket(s,ilen) ;
return writebuftosocket(s,buf,0,ilen,deallen,onsendtext) ;
}
catch(exception err)
{
messagebox.show("发送文本失败!"+err.message) ;
return false ;
}
}
/// <summary>
/// 将文件写到socket
/// </summary>
/// <param name="s">要发送文件的socket</param>
/// <param name="strfile">要发送的文件</param>
/// <returns>是否成功</returns>
public static bool writefiletosocket(socket s,string strfile,
onsend onsendfile)
{
filestream fs = new filestream(strfile,filemode.open,fileaccess.read,fileshare.read) ;
int ilen = (int)fs.length ;
writedynamiclentosocket(s,ilen) ;
byte [] buf = new byte[ilen] ;
try
{
fs.read(buf,0,ilen) ;
return writebuftosocket(s,buf,0,ilen,deallen,onsendfile) ;
}
catch(exception err)
{
messagebox.show("发送文件失败!"+err.message) ;
return false ;
}
finally
{
fs.close() ;
}
}
/// <summary>
/// 对方对自己消息的简单回应
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string readresponsionfromsocket( socket s)
{
byte [] bufcmd = new byte[responlen] ;
int icount = s.receive(bufcmd) ;
string strrespon = encoding.utf8.getstring(bufcmd,0,icount) ;
return strrespon ;
}
/// <summary>
/// 从socket读取命令
/// </summary>
/// <param name="s">要读取命令的socket</param>
/// <returns>读取的命令</returns>
public static string readcommandfromsocket( socket s)
{
byte [] bufcmd = new byte[cmdlen] ;
int icount = s.receive(bufcmd,0,cmdlen,socketflags.partial) ;
string strcommand = encoding.utf8.getstring(bufcmd,0,cmdlen) ;
return strcommand = strcommand.trimend(fillchar) ;
}
/// <summary>
/// 读取命令注释
/// </summary>
/// <param name="s">要读取命令注释的socket</param>
/// <returns>读取的命令注释</returns>
public static string readcommanddescfromsocket( socket s)
{
byte [] bufcmd = new byte[desclen] ;
int icount = s.receive(bufcmd,0,desclen,socketflags.partial) ;
string strcommand = encoding.utf8.getstring(bufcmd,0,desclen) ;
return strcommand = strcommand.trimend(fillchar) ;
}
/// <summary>
/// 读取可变部分的长度
/// </summary>
/// <param name="s">要读取可变部分长度的socket</param>
/// <returns>读取的可变部分的长度</returns>
public static int readdynamiclenfromsocket( socket s)
{
byte [] bufcmd = new byte[dynamiclengthlen] ;
int icount = s.receive(bufcmd,0,dynamiclengthlen,socketflags.partial) ;
string strcommand = encoding.utf8.getstring(bufcmd,0,dynamiclengthlen) ;
return int.parse(strcommand.trimend(fillchar)) ;
}
/// <summary>
/// 读取文本形式的可变信息
/// </summary>
/// <param name="s">要读取可变信息的socket</param>
/// <returns>读取的可变信息</returns>
public static string readdynamictextfromsocket( socket s)
{
int ilen = readdynamiclenfromsocket(s) ;
byte [] buf = new byte[ilen] ;
string strinfo = "" ;
int ireceiveded = 0 ;
int ireceiveing = 0 ;
while(ireceiveded<ilen)
{
if (ireceiveded + deallen <= ilen)
ireceiveing = deallen ;
else
ireceiveing = ilen - ireceiveded ;
s.receive(buf,ireceiveded,ireceiveing,socketflags.none) ;
communclass.writetexttosocket(s,"ok") ;
ireceiveded+= ireceiveing ;
}
strinfo = encoding.utf8.getstring(buf,0,ilen) ;
return strinfo ;
}
/// <summary>
/// 读取文件形式的可变信息
/// </summary>
/// <param name="s">要读取可变信息的socket</param>
/// <param name="strfile">读出后的文件保存位置</param>
/// <returns>是否读取成功</returns>
public static bool readdynamicfilefromsocket( socket s,string strfile)
{
int ilen = readdynamiclenfromsocket(s) ;
byte [] buf = new byte[ilen] ;
filestream fs = new filestream(strfile,filemode.create,fileaccess.write) ;
try
{
int ireceiveded = 0 ;
int ireceiveing = 0 ;
while(ireceiveded<ilen)
{
if (ireceiveded + deallen <= ilen)
ireceiveing = deallen ;
else
ireceiveing = ilen - ireceiveded ;
s.receive(buf,ireceiveded,ireceiveing,socketflags.none) ;
communclass.writetexttosocket(s,"ok") ;
ireceiveded+= ireceiveing ;
}
fs.write(buf,0,ilen) ;
return true ;
}
catch(exception err)
{
messagebox.show("接收文件失败"+err.message) ;
return false ;
}
finally
{
fs.close() ;
}
}
}//end class
}//end namespace
上面是俺的通讯基础类,有了这个类,再进行发送接受还不是小菜一碟吗?
未完待续