在 TCP 期间发送断点会影响结果
During TCP send breakpoint influences outcome
我正在编写的 Client/Server 应用程序有问题。它的目的是在客户端发送特定目录的文件并将它们发送到服务器上的目录。
我用 foreach 获取文件,但是当我在 foreach 的开头放置一个断点并继续发送直到我发送所有文件时,我根据需要将所有文件都放在我的服务器中,当我删除断点重新运行我的应用程序,我的服务器只收到部分文件,我不知道为什么。
我不确定,但我想这是一个线程问题,但不知道如何解决。
服务器:
static void Main(string[] args)
{
try
{
TcpListener listen = new TcpListener(3003);
TcpClient client;
int bufferSize = 1024;
NetworkStream netStream = null;
int bytesRead = 0;
int allBytesRead = 0;
// Start listening
listen.Start();
// Accept client
client = listen.AcceptTcpClient();
StreamReader reader = new StreamReader(client.GetStream());
netStream = client.GetStream();
string fileName;
bool endOfSend=false;
do
{
fileName = reader.ReadLine();
// Read length of incoming data
byte[] length = new byte[4];
bytesRead = netStream.Read(length, 0, 4);
int dataLength = BitConverter.ToInt32(length, 0);
// Read the data
int bytesLeft = dataLength;
byte[] data = new byte[dataLength];
while (bytesLeft > 0)
{
int nextPacketSize = (bytesLeft > bufferSize) ? bufferSize : bytesLeft;
bytesRead = netStream.Read(data, allBytesRead, nextPacketSize);
allBytesRead += bytesRead;
bytesLeft -= bytesRead;
}
allBytesRead = 0;
bytesLeft = 0;
bytesRead = 0;
// Save file to desktop
Console.WriteLine("File {0} received.", fileName);
File.WriteAllBytes(@"C:\Users\toto2\Desktop\" + fileName, data);
} while (!endOfSend);
netStream.Close();
client.Close();
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine("File Receiving fail." + ex.Message);
}
}
客户:
static void Main(string[] args)
{
try
{
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
int port = 3003;
TcpClient client = new TcpClient();
//NetworkStream netStream;
// Connect to server
try
{
client.Connect(new IPEndPoint(ipAddress, port));
Console.WriteLine("Connecté.....");
SendFiles(client);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
// Clean up
client.Close();
Console.Read();
}
catch (Exception ex)
{
Console.WriteLine("File Sending fail." + ex.Message);
}
}
public static void SendFiles(TcpClient cli) {
NetworkStream netS=cli.GetStream();
int bufferSize = 1024;
string[] files = Directory.GetFiles(@"C:\Users\toto\Mes Images\test");
StreamWriter writer = new StreamWriter(cli.GetStream());
foreach (string item in files)
{
writer.WriteLine(Path.GetFileName(item));
writer.Flush();
// Read bytes from image
byte[] data = File.ReadAllBytes(Path.GetFullPath(item));
// Build the package
byte[] dataLength = BitConverter.GetBytes(data.Length);
byte[] package = new byte[4 + data.Length];
dataLength.CopyTo(package, 0);
data.CopyTo(package, 4);
// Send to server
int bytesSent = 0;
int bytesLeft = package.Length;
while (bytesLeft > 0)
{
int nextPacketSize = (bytesLeft > bufferSize) ? bufferSize : bytesLeft;
netS.Write(package, bytesSent, nextPacketSize);
bytesSent += nextPacketSize;
bytesLeft -= nextPacketSize;
}
}
writer.Close();
netS.Close();
}
感谢任何愿意帮助我的人。
您可能想要实施并确认服务器已收到 1 个文件给客户端。然后指示客户端发送下一个文件。据我所知,您只是一次发送所有文件。以下是确认的简单实现。您应该能够根据您的场景获取其中的相关部分。
//
/* Server Program */
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
public class serv {
public static void Main() {
try {
IPAddress ipAd = IPAddress.Parse("172.21.5.99");
// use local m/c IP address, and
// use the same in the client
/* Initializes the Listener */
TcpListener myList=new TcpListener(ipAd,8001);
/* Start Listeneting at the specified port */
myList.Start();
Console.WriteLine("The server is running at port 8001...");
Console.WriteLine("The local End point is :" +
myList.LocalEndpoint );
Console.WriteLine("Waiting for a connection.....");
Socket s=myList.AcceptSocket();
Console.WriteLine("Connection accepted from " + s.RemoteEndPoint);
byte[] b=new byte[100];
int k=s.Receive(b);
Console.WriteLine("Recieved...");
for (int i=0;i<k;i++)
Console.Write(Convert.ToChar(b[i]));
ASCIIEncoding asen=new ASCIIEncoding();
s.Send(asen.GetBytes("The string was recieved by the server."));
Console.WriteLine("\nSent Acknowledgement");
/* clean up */
s.Close();
myList.Stop();
}
catch (Exception e) {
Console.WriteLine("Error..... " + e.StackTrace);
}
}
}
---------------------------------------------------------------------------
/* Client Program */
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Net.Sockets;
public class clnt {
public static void Main() {
try {
TcpClient tcpclnt = new TcpClient();
Console.WriteLine("Connecting.....");
tcpclnt.Connect("172.21.5.99",8001);
// use the ipaddress as in the server program
Console.WriteLine("Connected");
Console.Write("Enter the string to be transmitted : ");
String str=Console.ReadLine();
Stream stm = tcpclnt.GetStream();
ASCIIEncoding asen= new ASCIIEncoding();
byte[] ba=asen.GetBytes(str);
Console.WriteLine("Transmitting.....");
stm.Write(ba,0,ba.Length);
byte[] bb=new byte[100];
int k=stm.Read(bb,0,100);
for (int i=0;i<k;i++)
Console.Write(Convert.ToChar(bb[i]));
tcpclnt.Close();
}
catch (Exception e) {
Console.WriteLine("Error..... " + e.StackTrace);
}
}
}
您有一个混合 binary/text 协议。那可能很痛苦。 StreamReader
缓冲部分流。它需要超过它 returns 立即作为一个字符串。您不能将它与其他阅读器混用。
扔掉所有这些代码并使用更高级别的通信机制。例如,WCF 和用于二进制流的 MTOM。或 HTTP。
如果您不愿意使用 BinaryReader
广告 BinaryWriter
。它们相当易于使用。
请注意,当您读取长度时,您假设所有 4 个字节将在一次读取中到达。这个假设是错误的。
我正在编写的 Client/Server 应用程序有问题。它的目的是在客户端发送特定目录的文件并将它们发送到服务器上的目录。
我用 foreach 获取文件,但是当我在 foreach 的开头放置一个断点并继续发送直到我发送所有文件时,我根据需要将所有文件都放在我的服务器中,当我删除断点重新运行我的应用程序,我的服务器只收到部分文件,我不知道为什么。
我不确定,但我想这是一个线程问题,但不知道如何解决。
服务器:
static void Main(string[] args)
{
try
{
TcpListener listen = new TcpListener(3003);
TcpClient client;
int bufferSize = 1024;
NetworkStream netStream = null;
int bytesRead = 0;
int allBytesRead = 0;
// Start listening
listen.Start();
// Accept client
client = listen.AcceptTcpClient();
StreamReader reader = new StreamReader(client.GetStream());
netStream = client.GetStream();
string fileName;
bool endOfSend=false;
do
{
fileName = reader.ReadLine();
// Read length of incoming data
byte[] length = new byte[4];
bytesRead = netStream.Read(length, 0, 4);
int dataLength = BitConverter.ToInt32(length, 0);
// Read the data
int bytesLeft = dataLength;
byte[] data = new byte[dataLength];
while (bytesLeft > 0)
{
int nextPacketSize = (bytesLeft > bufferSize) ? bufferSize : bytesLeft;
bytesRead = netStream.Read(data, allBytesRead, nextPacketSize);
allBytesRead += bytesRead;
bytesLeft -= bytesRead;
}
allBytesRead = 0;
bytesLeft = 0;
bytesRead = 0;
// Save file to desktop
Console.WriteLine("File {0} received.", fileName);
File.WriteAllBytes(@"C:\Users\toto2\Desktop\" + fileName, data);
} while (!endOfSend);
netStream.Close();
client.Close();
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine("File Receiving fail." + ex.Message);
}
}
客户:
static void Main(string[] args)
{
try
{
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
int port = 3003;
TcpClient client = new TcpClient();
//NetworkStream netStream;
// Connect to server
try
{
client.Connect(new IPEndPoint(ipAddress, port));
Console.WriteLine("Connecté.....");
SendFiles(client);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
// Clean up
client.Close();
Console.Read();
}
catch (Exception ex)
{
Console.WriteLine("File Sending fail." + ex.Message);
}
}
public static void SendFiles(TcpClient cli) {
NetworkStream netS=cli.GetStream();
int bufferSize = 1024;
string[] files = Directory.GetFiles(@"C:\Users\toto\Mes Images\test");
StreamWriter writer = new StreamWriter(cli.GetStream());
foreach (string item in files)
{
writer.WriteLine(Path.GetFileName(item));
writer.Flush();
// Read bytes from image
byte[] data = File.ReadAllBytes(Path.GetFullPath(item));
// Build the package
byte[] dataLength = BitConverter.GetBytes(data.Length);
byte[] package = new byte[4 + data.Length];
dataLength.CopyTo(package, 0);
data.CopyTo(package, 4);
// Send to server
int bytesSent = 0;
int bytesLeft = package.Length;
while (bytesLeft > 0)
{
int nextPacketSize = (bytesLeft > bufferSize) ? bufferSize : bytesLeft;
netS.Write(package, bytesSent, nextPacketSize);
bytesSent += nextPacketSize;
bytesLeft -= nextPacketSize;
}
}
writer.Close();
netS.Close();
}
感谢任何愿意帮助我的人。
您可能想要实施并确认服务器已收到 1 个文件给客户端。然后指示客户端发送下一个文件。据我所知,您只是一次发送所有文件。以下是确认的简单实现。您应该能够根据您的场景获取其中的相关部分。
//
/* Server Program */
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
public class serv {
public static void Main() {
try {
IPAddress ipAd = IPAddress.Parse("172.21.5.99");
// use local m/c IP address, and
// use the same in the client
/* Initializes the Listener */
TcpListener myList=new TcpListener(ipAd,8001);
/* Start Listeneting at the specified port */
myList.Start();
Console.WriteLine("The server is running at port 8001...");
Console.WriteLine("The local End point is :" +
myList.LocalEndpoint );
Console.WriteLine("Waiting for a connection.....");
Socket s=myList.AcceptSocket();
Console.WriteLine("Connection accepted from " + s.RemoteEndPoint);
byte[] b=new byte[100];
int k=s.Receive(b);
Console.WriteLine("Recieved...");
for (int i=0;i<k;i++)
Console.Write(Convert.ToChar(b[i]));
ASCIIEncoding asen=new ASCIIEncoding();
s.Send(asen.GetBytes("The string was recieved by the server."));
Console.WriteLine("\nSent Acknowledgement");
/* clean up */
s.Close();
myList.Stop();
}
catch (Exception e) {
Console.WriteLine("Error..... " + e.StackTrace);
}
}
}
---------------------------------------------------------------------------
/* Client Program */
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Net.Sockets;
public class clnt {
public static void Main() {
try {
TcpClient tcpclnt = new TcpClient();
Console.WriteLine("Connecting.....");
tcpclnt.Connect("172.21.5.99",8001);
// use the ipaddress as in the server program
Console.WriteLine("Connected");
Console.Write("Enter the string to be transmitted : ");
String str=Console.ReadLine();
Stream stm = tcpclnt.GetStream();
ASCIIEncoding asen= new ASCIIEncoding();
byte[] ba=asen.GetBytes(str);
Console.WriteLine("Transmitting.....");
stm.Write(ba,0,ba.Length);
byte[] bb=new byte[100];
int k=stm.Read(bb,0,100);
for (int i=0;i<k;i++)
Console.Write(Convert.ToChar(bb[i]));
tcpclnt.Close();
}
catch (Exception e) {
Console.WriteLine("Error..... " + e.StackTrace);
}
}
}
您有一个混合 binary/text 协议。那可能很痛苦。 StreamReader
缓冲部分流。它需要超过它 returns 立即作为一个字符串。您不能将它与其他阅读器混用。
扔掉所有这些代码并使用更高级别的通信机制。例如,WCF 和用于二进制流的 MTOM。或 HTTP。
如果您不愿意使用 BinaryReader
广告 BinaryWriter
。它们相当易于使用。
请注意,当您读取长度时,您假设所有 4 个字节将在一次读取中到达。这个假设是错误的。