C# tcp发送消息和传输文件
最近做了一个双机备份,就是服务器上有个文件夹,会接收客户端传来的文件,而我们要做的就是同步这台服务器和另一台备用服务器上的文件.
为了实现这个功能我们使用的tcp点对点传输.
【背景】
最近做了一个双机备份,就是服务器上有个文件夹,会接收客户端传来的文件,而我们要做的就是同步这台服务器和另一台备用服务器上的文件.
为了实现这个功能我们使用的tcp点对点传输.
【开发环境】
VS2005
【实现原理】
要实现同步要解决两个问题,一个是获取本地服务器上上传上来的文件,二是实现两台机器间的文件传输.
第一个问题我们用的FileSystemWatcher这个可以监视指定文件夹下的文件变动,然后我们把变动的文件信息记录到数据库,在指定的时间间隔后同步两台机器的文件.
第二个问题我们用的tcp文件传输,我们按照一定的原则通过传输消息来告知备份服务器的要传输的文件名称和大小,然后传输文件.
【代码】
1:FileSystemWatcher监视文件变动的就不介绍了,很简单的winform控件应用.
2:为了完成文件传输,我做了一个TcpHelper类库,其中包括TcpCommon,TcpClientHelper,TcpListenerHelper三个类,TcpCommon主要实现了文件传输时用的一些公共的方法比如发送接收文件,发送接收消息,和文件hash的计算
TcpCommon
Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Net.Sockets;
namespace Xpwy.Backup.PTcpHelper
{
internal class TcpCommon
{
private static readonly int _blockLength = 500 * 1024;
/// <summary>
/// 计算文件的hash值
/// </summary>
internal string CalcFileHash(string FilePath)
{
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] hash;
using (FileStream fs = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096))
{
hash = md5.ComputeHash(fs);
}
return BitConverter.ToString(hash);
}
/// <summary>
/// 发送文件
/// </summary>
/// <param name="filePath"></param>
/// <param name="stream"></param>
/// <returns></returns>
internal bool SendFile(string filePath, NetworkStream stream)
{
FileStream fs = File.Open(filePath, FileMode.Open);
int readLength = 0;
byte[] data = new byte[_blockLength];
//发送大小
byte[] length = new byte[8];
BitConverter.GetBytes(new FileInfo(filePath).Length).CopyTo(length, 0);
stream.Write(length, 0, 8);
//发送文件
while ((readLength = fs.Read(data, 0, _blockLength)) > 0)
{
stream.Write(data, 0, readLength);
}
fs.Close();
return true;
}
/// <summary>
/// 接收文件
/// </summary>
/// <param name="filePath"></param>
/// <param name="stream"></param>
/// <returns></returns>
internal bool ReceiveFile(string filePath, NetworkStream stream)
{
try
{
long count = GetSize(stream);
if (count == 0)
{
return false;
}
long index = 0;
byte[] clientData = new byte[_blockLength];
if (File.Exists(filePath))
{
File.Delete(filePath);
}
string path=new FileInfo(filePath).Directory.FullName;
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
FileStream fs = File.Open(filePath, FileMode.OpenOrCreate);
try
{
//计算当前要读取的块的大小
int currentBlockLength = 0;
if (_blockLength < count - index)
{
currentBlockLength = _blockLength;
}
else
{
currentBlockLength =(int)( count - index);
}
int receivedBytesLen = stream.Read(clientData, 0, currentBlockLength);
index += receivedBytesLen;
fs.Write(clientData, 0, receivedBytesLen);
while (receivedBytesLen > 0 && index < count)
{
clientData = new byte[_blockLength];
receivedBytesLen = 0;
if (_blockLength < count - index)
{
currentBlockLength = _blockLength;
}
else
{
currentBlockLength = (int)(count - index);
}
receivedBytesLen = stream.Read(clientData, 0, currentBlockLength);
index += receivedBytesLen;
fs.Write(clientData, 0, receivedBytesLen);
}
}
catch (Exception ex)
{
return false;
}
finally
{
fs.Close();
}
}
catch (Exception ex)
{
return false;
}
return true;
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="message"></param>
/// <param name="stream"></param>
/// <returns></returns>
internal bool SendMessage(string message, NetworkStream stream)
{
byte[] data = Encoding.UTF8.GetBytes(message);
byte[] resultData = new byte[8 + data.Length];
BitConverter.GetBytes(data.Length).CopyTo(resultData, 0);
data.CopyTo(resultData, 8);
stream.Write(resultData, 0, resultData.Length);
return true;
}
/// <summary>
/// 读取消息
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
internal string ReadMessage(NetworkStream stream)
{
string result = "";
int messageLength = 0;
byte[] resultbyte = new byte[500 * 1024];
//读取数据大小
int index = 0;
int count = GetSize(stream);
byte[] data = new byte[count];
while (index < count && (messageLength = stream.Read(data, 0, count - index)) != 0)
{
data.CopyTo(resultbyte, index);
index += messageLength;
}
result = Encoding.UTF8.GetString(resultbyte, 0, index);
return result;
}
/// <summary>
/// 获取要读取的数据的大小
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
private int GetSize(NetworkStream stream)
{
int count = 0;
byte[] countBytes = new byte[8];
try
{
if (stream.Read(countBytes, 0, 8) == 8)
{
count = BitConverter.ToInt32(countBytes, 0);
}
else
{
return 0;
}
}
catch (Exception ex)
{
}
return count;
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Net.Sockets;
namespace Xpwy.Backup.PTcpHelper
{
internal class TcpCommon
{
private static readonly int _blockLength = 500 * 1024;
/// <summary>
/// 计算文件的hash值
/// </summary>
internal string CalcFileHash(string FilePath)
{
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] hash;
using (FileStream fs = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096))
{
hash = md5.ComputeHash(fs);
}
return BitConverter.ToString(hash);
}
/// <summary>
/// 发送文件
/// </summary>
/// <param name="filePath"></param>
/// <param name="stream"></param>
/// <returns></returns>
internal bool SendFile(string filePath, NetworkStream stream)
{
FileStream fs = File.Open(filePath, FileMode.Open);
int readLength = 0;
byte[] data = new byte[_blockLength];
//发送大小
byte[] length = new byte[8];
BitConverter.GetBytes(new FileInfo(filePath).Length).CopyTo(length, 0);
stream.Write(length, 0, 8);
//发送文件
while ((readLength = fs.Read(data, 0, _blockLength)) > 0)
{
stream.Write(data, 0, readLength);
}
fs.Close();
return true;
}
/// <summary>
/// 接收文件
/// </summary>
/// <param name="filePath"></param>
/// <param name="stream"></param>
/// <returns></returns>
internal bool ReceiveFile(string filePath, NetworkStream stream)
{
try
{
long count = GetSize(stream);
if (count == 0)
{
return false;
}
long index = 0;
byte[] clientData = new byte[_blockLength];
if (File.Exists(filePath))
{
File.Delete(filePath);
}
string path=new FileInfo(filePath).Directory.FullName;
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
FileStream fs = File.Open(filePath, FileMode.OpenOrCreate);
try
{
//计算当前要读取的块的大小
int currentBlockLength = 0;
if (_blockLength < count - index)
{
currentBlockLength = _blockLength;
}
else
{
currentBlockLength =(int)( count - index);
}
int receivedBytesLen = stream.Read(clientData, 0, currentBlockLength);
index += receivedBytesLen;
fs.Write(clientData, 0, receivedBytesLen);
while (receivedBytesLen > 0 && index < count)
{
clientData = new byte[_blockLength];
receivedBytesLen = 0;
if (_blockLength < count - index)
{
currentBlockLength = _blockLength;
}
else
{
currentBlockLength = (int)(count - index);
}
receivedBytesLen = stream.Read(clientData, 0, currentBlockLength);
index += receivedBytesLen;
fs.Write(clientData, 0, receivedBytesLen);
}
}
catch (Exception ex)
{
return false;
}
finally
{
fs.Close();
}
}
catch (Exception ex)
{
return false;
}
return true;
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="message"></param>
/// <param name="stream"></param>
/// <returns></returns>
internal bool SendMessage(string message, NetworkStream stream)
{
byte[] data = Encoding.UTF8.GetBytes(message);
byte[] resultData = new byte[8 + data.Length];
BitConverter.GetBytes(data.Length).CopyTo(resultData, 0);
data.CopyTo(resultData, 8);
stream.Write(resultData, 0, resultData.Length);
return true;
}
/// <summary>
/// 读取消息
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
internal string ReadMessage(NetworkStream stream)
{
string result = "";
int messageLength = 0;
byte[] resultbyte = new byte[500 * 1024];
//读取数据大小
int index = 0;
int count = GetSize(stream);
byte[] data = new byte[count];
while (index < count && (messageLength = stream.Read(data, 0, count - index)) != 0)
{
data.CopyTo(resultbyte, index);
index += messageLength;
}
result = Encoding.UTF8.GetString(resultbyte, 0, index);
return result;
}
/// <summary>
/// 获取要读取的数据的大小
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
private int GetSize(NetworkStream stream)
{
int count = 0;
byte[] countBytes = new byte[8];
try
{
if (stream.Read(countBytes, 0, 8) == 8)
{
count = BitConverter.ToInt32(countBytes, 0);
}
else
{
return 0;
}
}
catch (Exception ex)
{
}
return count;
}
}
}
TcpClientHelper
Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
namespace Xpwy.Backup.PTcpHelper
{
public class TcpClientHelper:IDisposable
{
TcpClient client;
NetworkStream netstream;
string _serverip = "127.0.0.1";
int _port = 8080;
TcpCommon tcpCommon = new TcpCommon();
#region TcpClientHelper constructor
public TcpClientHelper(string strServerIP, int serverPort)
{
_serverip = strServerIP;
_port = serverPort;
}
#endregion
public void Start()
{
client = new TcpClient(_serverip, _port);
netstream = client.GetStream();
}
public void Stop()
{
if (netstream != null)
{
netstream.Close();
}
if (client != null)
{
client.Close();
}
}
#region TcpCommon所有方法
public string CalcFileHash(string FilePath)
{
return tcpCommon.CalcFileHash(FilePath);
}
public bool SendFile(string filePath)
{
return tcpCommon.SendFile(filePath, netstream);
}
public bool ReceiveFile(string filePath)
{
return tcpCommon.ReceiveFile(filePath, netstream);
}
public bool SendMessage(string message)
{
return tcpCommon.SendMessage(message, netstream);
}
public string ReadMessage()
{
return tcpCommon.ReadMessage(netstream);
}
#endregion
#region IDisposable 成员
public void Dispose()
{
if (netstream != null)
{
netstream.Close();
}
if (client != null)
{
client.Close();
}
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
namespace Xpwy.Backup.PTcpHelper
{
public class TcpClientHelper:IDisposable
{
TcpClient client;
NetworkStream netstream;
string _serverip = "127.0.0.1";
int _port = 8080;
TcpCommon tcpCommon = new TcpCommon();
#region TcpClientHelper constructor
public TcpClientHelper(string strServerIP, int serverPort)
{
_serverip = strServerIP;
_port = serverPort;
}
#endregion
public void Start()
{
client = new TcpClient(_serverip, _port);
netstream = client.GetStream();
}
public void Stop()
{
if (netstream != null)
{
netstream.Close();
}
if (client != null)
{
client.Close();
}
}
#region TcpCommon所有方法
public string CalcFileHash(string FilePath)
{
return tcpCommon.CalcFileHash(FilePath);
}
public bool SendFile(string filePath)
{
return tcpCommon.SendFile(filePath, netstream);
}
public bool ReceiveFile(string filePath)
{
return tcpCommon.ReceiveFile(filePath, netstream);
}
public bool SendMessage(string message)
{
return tcpCommon.SendMessage(message, netstream);
}
public string ReadMessage()
{
return tcpCommon.ReadMessage(netstream);
}
#endregion
#region IDisposable 成员
public void Dispose()
{
if (netstream != null)
{
netstream.Close();
}
if (client != null)
{
client.Close();
}
}
#endregion
}
}
TcpListenerHelper
Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace Xpwy.Backup.PTcpHelper
{
public class TcpListenerHelper
{
private string _strServerIP = "";
private int _serverPort = 0;
TcpListener server;
TcpClient client;
NetworkStream netstream;
IAsyncResult asyncResult;
TcpCommon tcpCommon = new TcpCommon();
ManualResetEvent listenConnected = new ManualResetEvent(false);
bool _active = false;
public TcpListenerHelper(string strServerIP, int serverPort)
{
_strServerIP = strServerIP;
_serverPort = serverPort;
server = new TcpListener(IPAddress.Parse(strServerIP), serverPort);
server.Server.ReceiveTimeout = 6000;
server.Server.SendTimeout = 6000;
}
/// <summary>
/// 启动
/// </summary>
public void Start()
{
try
{
_active = true;
server.Start();
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 停止
/// </summary>
public void Stop()
{
try
{
_active = false;
if (client != null)
{
client.Close();
}
if (netstream != null)
{
netstream.Close();
}
server.Stop();
}
catch (Exception ex)
{
throw ex;
}
}
public void Listen()
{
listenConnected.Reset();
asyncResult = server.BeginAcceptTcpClient(new AsyncCallback(AsyncCall), server);
}
public void AsyncCall(IAsyncResult ar)
{
try
{
TcpListener tlistener = (TcpListener)ar.AsyncState;
if (_active)
{
client = tlistener.EndAcceptTcpClient(ar);
netstream = client.GetStream();
}
else
{
client = null;
netstream = null;
}
listenConnected.Set();
}
catch (Exception ex)
{
throw ex;
}
}
public bool WaitForConnect()
{
listenConnected.WaitOne();
if (client != null && netstream != null)
{
return true;
}
else
{
return false;
}
}
#region TcpCommon所有方法
/// <summary>
/// 计算文件的hash值
/// </summary>
public string CalcFileHash(string FilePath)
{
return tcpCommon.CalcFileHash(FilePath);
}
/// <summary>
/// 发送文件
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public bool SendFile(string filePath)
{
return tcpCommon.SendFile(filePath, netstream);
}
/// <summary>
/// 接收文件
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public bool ReceiveFile(string filePath)
{
return tcpCommon.ReceiveFile(filePath, netstream);
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public bool SendMessage(string message)
{
return tcpCommon.SendMessage(message, netstream);
}
/// <summary>
/// 接收消息
/// </summary>
/// <returns></returns>
public string ReadMessage()
{
return tcpCommon.ReadMessage(netstream);
}
#endregion
#region IDisposable 成员
public void Dispose()
{
Stop();
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace Xpwy.Backup.PTcpHelper
{
public class TcpListenerHelper
{
private string _strServerIP = "";
private int _serverPort = 0;
TcpListener server;
TcpClient client;
NetworkStream netstream;
IAsyncResult asyncResult;
TcpCommon tcpCommon = new TcpCommon();
ManualResetEvent listenConnected = new ManualResetEvent(false);
bool _active = false;
public TcpListenerHelper(string strServerIP, int serverPort)
{
_strServerIP = strServerIP;
_serverPort = serverPort;
server = new TcpListener(IPAddress.Parse(strServerIP), serverPort);
server.Server.ReceiveTimeout = 6000;
server.Server.SendTimeout = 6000;
}
/// <summary>
/// 启动
/// </summary>
public void Start()
{
try
{
_active = true;
server.Start();
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 停止
/// </summary>
public void Stop()
{
try
{
_active = false;
if (client != null)
{
client.Close();
}
if (netstream != null)
{
netstream.Close();
}
server.Stop();
}
catch (Exception ex)
{
throw ex;
}
}
public void Listen()
{
listenConnected.Reset();
asyncResult = server.BeginAcceptTcpClient(new AsyncCallback(AsyncCall), server);
}
public void AsyncCall(IAsyncResult ar)
{
try
{
TcpListener tlistener = (TcpListener)ar.AsyncState;
if (_active)
{
client = tlistener.EndAcceptTcpClient(ar);
netstream = client.GetStream();
}
else
{
client = null;
netstream = null;
}
listenConnected.Set();
}
catch (Exception ex)
{
throw ex;
}
}
public bool WaitForConnect()
{
listenConnected.WaitOne();
if (client != null && netstream != null)
{
return true;
}
else
{
return false;
}
}
#region TcpCommon所有方法
/// <summary>
/// 计算文件的hash值
/// </summary>
public string CalcFileHash(string FilePath)
{
return tcpCommon.CalcFileHash(FilePath);
}
/// <summary>
/// 发送文件
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public bool SendFile(string filePath)
{
return tcpCommon.SendFile(filePath, netstream);
}
/// <summary>
/// 接收文件
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public bool ReceiveFile(string filePath)
{
return tcpCommon.ReceiveFile(filePath, netstream);
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public bool SendMessage(string message)
{
return tcpCommon.SendMessage(message, netstream);
}
/// <summary>
/// 接收消息
/// </summary>
/// <returns></returns>
public string ReadMessage()
{
return tcpCommon.ReadMessage(netstream);
}
#endregion
#region IDisposable 成员
public void Dispose()
{
Stop();
}
#endregion
}
}
3:调用的代码
server端:
Code
public void DoWork(object state)
{
TcpListenerHelper tlistener = (TcpListenerHelper)state;
tlistener.Listen();//监听
while (tlistener.WaitForConnect())//等待知道监听到了连接
{
try
{
string firstMessage = "";
while (!string.IsNullOrEmpty((firstMessage = tlistener.ReadMessage())))
{
if (firstMessage.ToLower() == "filebak".ToLower())
{
tlistener.SendMessage("filebakok");
#region 文件备份
string filepath = Path.Combine(Environment.CurrentDirectory, "FileBak\\" + tlistener.ReadMessage()).ToString();
tlistener.ReceiveFile(filepath);
if (tlistener.CalcFileHash(filepath) == tlistener.ReadMessage())
{
tlistener.SendMessage("ok");
}
else
{
tlistener.SendMessage("wrong");
}
#endregion
}
else if (firstMessage.ToLower() == "DBBak".ToLower())
{
#region 数据库备份
tlistener.SendMessage("dbbakok");
string filename = tlistener.ReadMessage();
string filepath = Path.Combine(System.Environment.CurrentDirectory, "DBBak") +"\\"+ filename;
//接收文件
tlistener.ReceiveFile(filepath);
//验证hash值
string hash = tlistener.ReadMessage();
if (hash == tlistener.CalcFileHash(filepath))
tlistener.SendMessage("ok");
else
tlistener.SendMessage("wrong");
#endregion
}
}
}
catch
{
}
tlistener.Listen();//监听下一个连接
}
}
public void DoWork(object state)
{
TcpListenerHelper tlistener = (TcpListenerHelper)state;
tlistener.Listen();//监听
while (tlistener.WaitForConnect())//等待知道监听到了连接
{
try
{
string firstMessage = "";
while (!string.IsNullOrEmpty((firstMessage = tlistener.ReadMessage())))
{
if (firstMessage.ToLower() == "filebak".ToLower())
{
tlistener.SendMessage("filebakok");
#region 文件备份
string filepath = Path.Combine(Environment.CurrentDirectory, "FileBak\\" + tlistener.ReadMessage()).ToString();
tlistener.ReceiveFile(filepath);
if (tlistener.CalcFileHash(filepath) == tlistener.ReadMessage())
{
tlistener.SendMessage("ok");
}
else
{
tlistener.SendMessage("wrong");
}
#endregion
}
else if (firstMessage.ToLower() == "DBBak".ToLower())
{
#region 数据库备份
tlistener.SendMessage("dbbakok");
string filename = tlistener.ReadMessage();
string filepath = Path.Combine(System.Environment.CurrentDirectory, "DBBak") +"\\"+ filename;
//接收文件
tlistener.ReceiveFile(filepath);
//验证hash值
string hash = tlistener.ReadMessage();
if (hash == tlistener.CalcFileHash(filepath))
tlistener.SendMessage("ok");
else
tlistener.SendMessage("wrong");
#endregion
}
}
}
catch
{
}
tlistener.Listen();//监听下一个连接
}
}
client端:
Code
private void FileBackup(object arg)
{
TcpClientHelper client = (TcpClientHelper)arg;
//获取需备份的文件
DataTable dt = this._oFileWatch.GetBackupFiles();
if (dt != null)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
client.SendMessage("FileBak");
if (client.ReadMessage().ToLower() == "filebakok")
{
client.SendMessage(dt.Rows[i]["RelativePath"].ToString());
client.SendFile(dt.Rows[i]["FullPath"].ToString());
client.SendMessage(client.CalcFileHash(dt.Rows[i]["FullPath"].ToString()));
if (client.ReadMessage().ToLower() == "ok")
{
LOGClass.WriteLog("备份文件【" + dt.Rows[i]["FullPath"].ToString() + "】成功");
}
else
{
LOGClass.WriteLog("备份文件【" + dt.Rows[i]["FullPath"].ToString() + "】失败。");
}
}
}
this._oFileWatch.ClearTmp();
}
}
private void FileBackup(object arg)
{
TcpClientHelper client = (TcpClientHelper)arg;
//获取需备份的文件
DataTable dt = this._oFileWatch.GetBackupFiles();
if (dt != null)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
client.SendMessage("FileBak");
if (client.ReadMessage().ToLower() == "filebakok")
{
client.SendMessage(dt.Rows[i]["RelativePath"].ToString());
client.SendFile(dt.Rows[i]["FullPath"].ToString());
client.SendMessage(client.CalcFileHash(dt.Rows[i]["FullPath"].ToString()));
if (client.ReadMessage().ToLower() == "ok")
{
LOGClass.WriteLog("备份文件【" + dt.Rows[i]["FullPath"].ToString() + "】成功");
}
else
{
LOGClass.WriteLog("备份文件【" + dt.Rows[i]["FullPath"].ToString() + "】失败。");
}
}
}
this._oFileWatch.ClearTmp();
}
}
【TcpHelper代码】
本站文章除做特殊声明则一律属于原创,转载请注明出处
--周瑞喜(rain.zhou)
开源分享使人进步,使技术进步,使社会进步