想实现的效果是 //客户端指定一个文件夹,将文件夹下所有文件都传到服务端。
客户端首先遍历子文件,获取文件名,发送文件名,将文件内容转成byte[],然后发送,发送下一个文件名
//服务端用的是
TcpListener tcpListener = new TcpListener(ipPoint);
tcpListener.Start(); //这个的问题是,只能监听到第一个文件,其他的文件监听不到了
//改进方案,发送的时候将文件夹中存在的文件数量传过来
while (true)
{
//如果没有Connect请求
if (!tcpListener.Pending()) //LineXXX
{
Thread.Sleep(1000);
continue;
}
else
{
//接收文件名,创建文件,写入文件内容。这样完成了一个文件。BlockBBB
}
} 问题出来了,在LineXXX这个地方,第一次没有问题,也就是能够执行BlockBBB.但是,第一次后,再次到LineXXX,这个地方就总是监听不到发送端的 Send(Socket,byte[])了。何解?
客户端首先遍历子文件,获取文件名,发送文件名,将文件内容转成byte[],然后发送,发送下一个文件名
//服务端用的是
TcpListener tcpListener = new TcpListener(ipPoint);
tcpListener.Start(); //这个的问题是,只能监听到第一个文件,其他的文件监听不到了
//改进方案,发送的时候将文件夹中存在的文件数量传过来
while (true)
{
//如果没有Connect请求
if (!tcpListener.Pending()) //LineXXX
{
Thread.Sleep(1000);
continue;
}
else
{
//接收文件名,创建文件,写入文件内容。这样完成了一个文件。BlockBBB
}
} 问题出来了,在LineXXX这个地方,第一次没有问题,也就是能够执行BlockBBB.但是,第一次后,再次到LineXXX,这个地方就总是监听不到发送端的 Send(Socket,byte[])了。何解?
{
Socket serversocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
serversocket.Bind(iPoint);
serversocket.Listen(20);
while (true)
{
Socket socket = serversocket.Accept();
byte[] buffer = new byte[1024];
int receiveCount = socket.Receive(buffer);
if (receiveCount > 0)
{
string msg = Encoding.UTF8.GetString(buffer, 0, receiveCount);
}
else
{
socket.Close();
break;
}
}
}
{
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("192.168.1.44"), 8888);
client.Connect(ipPoint);
DirectoryInfo di = new DirectoryInfo(fb.SelectedPath);
foreach (FileInfo fi in di.GetFiles())
{
//发送文件名
string filename = fi.Name;
byte[] bt_filename = System.Text.Encoding.Unicode.GetBytes(filename);
SendVarData(client, bt_filename); byte[] bt_data = new byte[50000];
FileStream fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read);
//文件大于50000字节
if (fs.Length >= 50000)
{
//发送整包
int count = (int)(fs.Length / 50000);
for (int i = 0; i <= count - 1; i++)
{
fs.Read(bt_data, 0, bt_data.Length);
SendVarData(client, bt_data);
//整包发送完,停顿0.05s
Thread.Sleep(50);
}
//发送余包
byte[] bt_dataleft = new byte[fs.Length % 500000];
fs.Read(bt_dataleft, 0, bt_dataleft.Length);
SendVarData(client, bt_dataleft);
} //文件小于50000字节
else
{
//byte[]中存在元素是空
fs.Read(bt_data, 0, bt_data.Length);
SendVarData(client, bt_data);
}
fs.Close();
}
client.Close();
}
//接收端代码
private void StartReceive()
{
//监听所有ip
//IPEndPoint ipPoint = new IPEndPoint(IPAddress.Any, 8888);
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("192.168.1.44"), 8888);
TcpListener tcpListener = new TcpListener(ipPoint);
tcpListener.Start();
while (true)
{
//如果没有Connect请求
if (!tcpListener.Pending())
{
Thread.Sleep(1000);
continue;
} //如果有Connect请求
Socket client = tcpListener.AcceptSocket();
byte[] byte_filename = ReceiveVarData(client);
string filename = System.Text.Encoding.Unicode.GetString(byte_filename);
//创建文件
FileStream fs = new FileStream(dir + "\\" + filename, FileMode.OpenOrCreate, FileAccess.Write); //向文件中写入数据
while (true)
{
//每次后台返回的就只是一部分
byte[] data = ReceiveVarData(client);
if (data.Length == 0)
{
break;
} else
{
//写完一段data后,fs在文件中的位置停留在文件末尾,下次循环时,直接追加在文件结尾
fs.Write(data, 0, data.Length);
}
}
//关闭文件
fs.Close();
}
}
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("192.168.1.44"), 8888);
client.Connect(ipPoint);
放到你的SendVarData这个方法的最前面去,应该就可以了。记得要关闭掉socket。
不然你就用异步发送。Socket client = tcpListener.AcceptSocket();
每次接受到一个新socket后才会往下走的,如果这么做的话,你的Listen(20)可能不太够,你还要开个线程去处理那些已经关闭的socket。
public static int SendVarData(Socket s, byte[] data)
{
int total = 0;
int size = data.Length;
int dataleft = size;
int sent; //这次发送让我很费解,不过去掉的话,程序就不可用
byte[] datasize = new byte[4];
//文件名png.png 被转成了byte[14],这个是将存到datasize[0]中
datasize = BitConverter.GetBytes(size); //第一次发出的byte数
//发文件名时,只循环了次
sent = s.Send(datasize);
//这次发送让我很费解 while (total < size)
{
sent = s.Send(data, total, dataleft, SocketFlags.None);
total += sent;
dataleft -= sent;
}
return total;
} //接收数据
public static byte[] ReceiveVarData(Socket s)
{
int total = 0;
int recv; //这次接收是为了干嘛?
byte[] datasize = new byte[4];
recv = s.Receive(datasize, 0, 4, SocketFlags.None);
//这次接收是为了干嘛?
int size = BitConverter.ToInt32(datasize, 0);
int dataleft = size;
byte[] data = new byte[size];
while (total < size)
{
recv = s.Receive(data, total, dataleft, SocketFlags.None);
if (recv == 0)
{
data = null;
break;
}
total += recv;
dataleft -= recv;
}
return data;
}
你的第一个问题
很简单,你发送了,服务器也接收了。但是呢,你的服务器只是接收了一次。所以你只能收到第一次发送的内容。
你服务器的监听知道用一个循环来监听,接收是一样的,你只接收了一次。
第二个问题://接收数据
public static byte[] ReceiveVarData(Socket s)
{
int total = 0;
int recv; //这次接收是为了干嘛?!!!!!!很明显,人家这是做了一个协议。第一次取出了这个包中数据 的长度,好在接收的时候不会少接收(丢包)或多接收(粘包)。你看一下发送端,一定有一个类或结构体,
使用encoding.ascii.getbytes(长度);就可以将一个长度转换成二进制数组。此处的byte【4】就是取出原来存的数。
byte[] datasize = new byte[4];
recv = s.Receive(datasize, 0, 4, SocketFlags.None);
//这次接收是为了干嘛?
int size = BitConverter.ToInt32(datasize, 0);
int dataleft = size;
byte[] data = new byte[size];
while (total < size)//这里只是第一次接收
{
recv = s.Receive(data, total, dataleft, SocketFlags.None);
if (recv == 0)
{
data = null;
break;
}
total += recv;
dataleft -= recv;
}//第一次接收结束之后,你没进行第二次的接收。
return data;
}其实你客户端的数据都已经发送到服务器了,都在缓冲区中,你没有读出来
传文件夹,这个已经是最基础的了,“丢包、粘包、内容校验”我的子文件全是2kb的txt,单包大小是50m,试验数据设计上就已经回避了丢包、粘包、内容校验。
那这点问题就难不倒你,小case,本机测试还是局域网测试?本机的不能信!~
传文件夹就不一样了
(2)StartReceive() 中没接收完一个文件,就就关闭一次Socket.
这样做,接收端的收到的byte[] data不会被写入同一个文件中。“跟踪显示所有文件信息已经发送”、“但是在接收端只收到一个文件”,是因为发送的所有的文件信息被写到1个文件中去了,楼主收到的那个文件中,包含了发送端7个文件的信息。
//接收端
private void StartReceive()
{
//监听所有ip
//IPEndPoint ipPoint = new IPEndPoint(IPAddress.Any, 8888);
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("192.168.1.44"), 8888);
TcpListener tcpListener = new TcpListener(ipPoint);
tcpListener.Start();
while (true)
{
//如果没有Connect请求
if (!tcpListener.Pending())
{
Thread.Sleep(1000);
continue;
} //如果有Connect请求
//创建接收端Socket
Socket client = tcpListener.AcceptSocket();
byte[] byte_filename = ReceiveVarData(client);
string filename = System.Text.Encoding.Unicode.GetString(byte_filename);
//创建文件
FileStream fs = new FileStream(dir + "\\" + filename, FileMode.OpenOrCreate, FileAccess.Write); //向文件中写入数据
while (true)
{
//每次后台返回的就只是一部分
byte[] data = ReceiveVarData(client);
if (data.Length == 0)
{
break;
} else
{
//写完一段data后,fs在文件中的位置停留在文件末尾,下次循环时,直接追加在文件结尾
fs.Write(data, 0, data.Length);
}
}
//关闭文件
fs.Close();
//每接收完一个文件,要关闭Socket,否则接收的数据被写入一个文件
client.Close();
}
}//发送端//发送文件夹中所有子文件
private void UpLoadFolder()
{
DirectoryInfo di = new DirectoryInfo(fb.SelectedPath);
foreach (FileInfo fi in di.GetFiles())
{ Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("192.168.1.44"), 8888);
client.Connect(ipPoint); //发送文件名
string filename = fi.Name;
byte[] bt_filename = System.Text.Encoding.Unicode.GetBytes(filename);
SendVarData(client, bt_filename); byte[] bt_data = new byte[50000];
FileStream fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read);
//文件大于50000字节
if (fs.Length >= 50000)
{
//发送整包
int count = (int)(fs.Length / 50000);
for (int i = 0; i <= count - 1; i++)
{
fs.Read(bt_data, 0, bt_data.Length);
SendVarData(client, bt_data);
//整包发送完,停顿0.05s
Thread.Sleep(50);
}
//发送余包
byte[] bt_dataleft = new byte[fs.Length % 500000];
fs.Read(bt_dataleft, 0, bt_dataleft.Length);
SendVarData(client, bt_dataleft);
} //文件小于50000字节
else
{
//byte[]中存在元素是空
fs.Read(bt_data, 0, bt_data.Length);
SendVarData(client, bt_data);
}
//每次传完一个文件,必须关闭Socket,否则多个文件的内容会写到一个文件中去。
fs.Close();
client.Close();
}
}
private void UpLoadFolder()
{
DirectoryInfo di = new DirectoryInfo(fb.SelectedPath);
foreach (FileInfo fi in di.GetFiles())
{ Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("192.168.1.44"), 8888);
client.Connect(ipPoint); //发送文件名
string filename = fi.Name;
byte[] bt_filename = System.Text.Encoding.Unicode.GetBytes(filename);
SendVarData(client, bt_filename); byte[] bt_data = new byte[50000];
FileStream fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read);
//文件大于50000字节
if (fs.Length >= 50000)
{
//发送整包
int count = (int)(fs.Length / 50000);
for (int i = 0; i <= count - 1; i++)
{
fs.Read(bt_data, 0, bt_data.Length);
SendVarData(client, bt_data);
//整包发送完,停顿0.05s
Thread.Sleep(50);
}
//发送余包
byte[] bt_dataleft = new byte[fs.Length % 500000];
fs.Read(bt_dataleft, 0, bt_dataleft.Length);
SendVarData(client, bt_dataleft);
} //文件小于50000字节
else
{
//byte[]中存在元素是空
fs.Read(bt_data, 0, bt_data.Length);
SendVarData(client, bt_data);
}
//每次传完一个文件,必须关闭Socket,否则多个文件的内容会写到一个文件中去。
fs.Close();
client.Close();
}
}
现在看到另一个问题
Send端的文件夹下 7个1kb的txt,到了接收夹中就成了7个50kb的,文件大小变大了~~
private void UpLoadFolder()
{
DirectoryInfo di = new DirectoryInfo(fb.SelectedPath);
foreach (FileInfo fi in di.GetFiles())
{ Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("192.168.1.44"), 8888);
client.Connect(ipPoint); //发送文件名
string filename = fi.Name;
byte[] bt_filename = System.Text.Encoding.Unicode.GetBytes(filename);
SendVarData(client, bt_filename); //byte[] bt_data = new byte[50000];
FileStream fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read);
//文件大于50000字节
if (fs.Length >= 50000)
{
//发送整包
byte[] bt_data = new byte[50000];
int count = (int)(fs.Length / 50000);
for (int i = 0; i <= count - 1; i++)
{
fs.Read(bt_data, 0, bt_data.Length);
SendVarData(client, bt_data);
//整包发送完,停顿0.05s
Thread.Sleep(50);
}
//发送余包
byte[] bt_dataleft = new byte[fs.Length % 500000];
fs.Read(bt_dataleft, 0, bt_dataleft.Length);
SendVarData(client, bt_dataleft);
} //文件小于50000字节
else
{
//byte[]中存在元素是空
byte[] bt_data = new byte[(int)(fs.Length)];
fs.Read(bt_data, 0, (int)(bt_data.Length));
SendVarData(client, bt_data);
}
//每次传完一个文件,必须关闭Socket,否则多个文件的内容会写到一个文件中去。
fs.Close();
client.Close();
}
}
AsyncCallback 这个回调函数 方法