当您通过 TCP 连接时,您会创建一个可以读取和写入的网络流,类似于您使用的所有其他流。将大量数据写入流不是一个好主意,因此我建议您将选定的文件分成较小的数据包,其中每个数据包长度为 1024 字节(1KB),然后将所有数据包发送到服务器。 SendTCP 函数如下:(我使用了 Windows 窗体来使事情更明显)
public void SendTCP(string M, string IPA, Int32 PortN)
{
byte[] SendingBuffer = null
TcpClient client = null;
lblStatus.Text = "";
NetworkStream netstream = null;
try
{
client = new TcpClient(IPA, PortN);
lblStatus.Text = "Connected to the Server...\n";
netstream = client.GetStream();
FileStream Fs = new FileStream(M, FileMode.Open, FileAccess.Read);
int NoOfPackets = Convert.ToInt32
(Math.Ceiling(Convert.ToDouble(Fs.Length) / Convert.ToDouble(BufferSize)));
progressBar1.Maximum = NoOfPackets;
int TotalLength = (int)Fs.Length, CurrentPacketLength, counter = 0;
for (int i = 0; i < NoOfPackets; i++)
{
if (TotalLength > BufferSize)
{
CurrentPacketLength = BufferSize;
TotalLength = TotalLength - CurrentPacketLength;
}
else
CurrentPacketLength = TotalLength;
SendingBuffer = new byte[CurrentPacketLength];
Fs.Read(SendingBuffer, 0, CurrentPacketLength);
netstream.Write(SendingBuffer, 0, (int)SendingBuffer.Length);
if (progressBar1.Value >= progressBar1.Maximum)
progressBar1.Value = progressBar1.Minimum;
progressBar1.PerformStep();
}
lblStatus.Text=lblStatus.Text+"Sent "+Fs.Length.ToString()+"
bytes to the server";
Fs.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
netstream.Close();
client.Close();
}
}
如您所见,正在构建 TCP 客户端和网络流,并启动网络连接。根据 1024 字节的缓冲区大小打开所选文件后,计算将要发送的数据包数。还有另外两个变量 CurrentPacketLength 和 TotalLength。如果所选文件的总长度大于缓冲区大小,则将 CurrentPacketLength 设置为缓冲区大小,否则为什么要发送一些空字节,因此将 CurrentPacketLength 设置为文件的总长度。之后,我从总长度中减去当前,所以实际上我们可以说总长度表示尚未发送的数据总量。剩下的就很简单了,从文件流中读取数据并根据 CurrentPacketLength 将其写入 SendingBuffer 并将缓冲区写入网络流。
在服务器端,应用程序正在侦听传入连接:
public void ReceiveTCP(int portN)
{
TcpListener Listener = null;
try
{
Listener = new TcpListener(IPAddress.Any, portN);
Listener.Start();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
byte[] RecData = new byte[BufferSize];
int RecBytes;
for (; ; )
{
TcpClient client = null;
NetworkStream netstream = null;
Status = string.Empty;
try
{
string message = "Accept the Incoming File ";
string caption = "Incoming Connection";
MessageBoxButtons buttons = MessageBoxButtons.YesNo;
DialogResult result;
if (Listener.Pending())
{
client = Listener.AcceptTcpClient();
netstream = client.GetStream();
Status = "Connected to a client\n";
result = MessageBox.Show(message, caption, buttons);
if (result == System.Windows.Forms.DialogResult.Yes)
{
string SaveFileName=string.Empty;
SaveFileDialog DialogSave = new SaveFileDialog();
DialogSave.Filter = "All files (*.*)|*.*";
DialogSave.RestoreDirectory = true;
DialogSave.Title = "Where do you want to save the file?";
DialogSave.InitialDirectory = @"C:/";
if (DialogSave.ShowDialog() == DialogResult.OK)
SaveFileName = DialogSave.FileName;
if (SaveFileName != string.Empty)
{
int totalrecbytes = 0;
FileStream Fs = new FileStream
(SaveFileName, FileMode.OpenOrCreate, FileAccess.Write);
while ((RecBytes = netstream.Read
(RecData, 0, RecData.Length)) > 0)
{
Fs.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
Fs.Close();
}
netstream.Close();
client.Close();
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
//netstream.Close();
}
}
}
创建了一个 TCP 侦听器并开始侦听指定的端口。缓冲区大小再次设置为 1024 字节。 TCP 侦听器可以在调用 AcceptTcpClient 方法之前预先检查是否有任何连接挂起。如果有任何挂起的连接,则返回 true。这种方法是避免套接字被阻塞的好方法。在从网络流中读取任何内容之前,会出现一个消息框询问您是否要接受传入的连接,然后会打开一个 SaveFileDialog,当您输入文件名和扩展名时,将构建一个文件流并开始读取网络流和写入文件流。在您的代码中创建一个线程并在创建的线程中运行接收方法。我已经使用该应用程序在 LAN 中发送了超过 100 MB 的文件。
更多详情,请查看article。