100分求救 Socket 接收端为何只能监听到一次发送端的行为?

hinada99 2011-03-29 05:18:42
想实现的效果是

//客户端指定一个文件夹,将文件夹下所有文件都传到服务端。
客户端首先遍历子文件,获取文件名,发送文件名,将文件内容转成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[])了。何解?
...全文
797 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
hinada99 2011-03-30
  • 打赏
  • 举报
回复
异步?
ycproc 2011-03-30
  • 打赏
  • 举报
回复
你做 异步的 监听回调
AsyncCallback 这个回调函数 方法
hinada99 2011-03-30
  • 打赏
  • 举报
回复
发送端作如下修改,接收到的文件与发送的文件同大

//发送文件夹中所有子文件
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();
}
}
hinada99 2011-03-30
  • 打赏
  • 举报
回复
文件传输问题解决了
现在看到另一个问题
Send端的文件夹下 7个1kb的txt,到了接收夹中就成了7个50kb的,文件大小变大了~~
hinada99 2011-03-30
  • 打赏
  • 举报
回复
To 21#
"因为发送的所有的文件信息被写到1个文件中去了,楼主收到的那个文件中,包含了发送端7个文件的信息。"
果然如此~~
Abafi 2011-03-30
  • 打赏
  • 举报
回复
//发送端

//发送文件夹中所有子文件
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();
}
}


Abafi 2011-03-30
  • 打赏
  • 举报
回复
小改两处(1)UpLoadFolder()中每传完一个文件,就关闭一次Socket。
(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();
}
}


itneste 2011-03-30
  • 打赏
  • 举报
回复
单包大小50m那是不可能的。。。socket自动帮你分包了。。。,如果就做一个传文件的小demo,不发送消息,一启动就传文件,那这样的很好做了。
传文件夹就不一样了。。。
hinada99 2011-03-30
  • 打赏
  • 举报
回复
局域网
原来 2011-03-30
  • 打赏
  • 举报
回复
发没有问题,接也没有问题,但要发并接的话有问题,说明两者没有结合好!!
itneste 2011-03-30
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 hinada99 的回复:]

单文件传输 已经写出。10个G的单文件测试,已通过,很基础~
传文件夹,这个已经是最基础的了,“丢包、粘包、内容校验”我的子文件全是2kb的txt,单包大小是50m,试验数据设计上就已经回避了丢包、粘包、内容校验。
[/Quote]

那这点问题就难不倒你,小case,本机测试还是局域网测试?本机的不能信!~
se7en 2011-03-30
  • 打赏
  • 举报
回复
3楼的可以用 。
hinada99 2011-03-30
  • 打赏
  • 举报
回复
单文件传输 已经写出。10个G的单文件测试,已通过,很基础~
传文件夹,这个已经是最基础的了,“丢包、粘包、内容校验”我的子文件全是2kb的txt,单包大小是50m,试验数据设计上就已经回避了丢包、粘包、内容校验。
itneste 2011-03-30
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 hinada99 的回复:]

函数都在,改哪处?
改不出来,求发送文件夹的代码~
[/Quote]

如果刚学习网络编程的话 建议先写最简单的,连接,发送,关闭,这种的,从最简单的做起,然后你就会发现随着你能力的增长,这种简单的不适合了,然后你就希望能够跟聊天一样,不能只发送一次就断开,我希望自己控制,想发送多少就发送多少次,再往后就是文件的传输了,文件传输比聊天难点,因为这中间要解决很多问题,比如丢包,粘包,内容的校验。。。。,你这个程序不难,但是初学者不容易理解。所以建议从最简单的写。。。个人建议。。。。
hinada99 2011-03-30
  • 打赏
  • 举报
回复
函数都在,改哪处?
改不出来,求发送文件夹的代码~
itneste 2011-03-30
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 hinada99 的回复:]

SendVarData\ReceiveVarData使用的是大众版~~已经过测试。
C# code

//发送数据
public static int SendVarData(Socket s, byte[] data)
{
int total = 0;
int size = data.Lengt……
[/Quote]

你的第一个问题
很简单,你发送了,服务器也接收了。但是呢,你的服务器只是接收了一次。所以你只能收到第一次发送的内容。
你服务器的监听知道用一个循环来监听,接收是一样的,你只接收了一次。
第二个问题:

//接收数据
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;
}



其实你客户端的数据都已经发送到服务器了,都在缓冲区中,你没有读出来。。。
hinada99 2011-03-30
  • 打赏
  • 举报
回复
SendVarData\ReceiveVarData使用的是大众版~~已经过测试。

//发送数据
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;
}




GabrielCNMao 2011-03-30
  • 打赏
  • 举报
回复
你把UpLoadFolder()这个方法的
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。
genius_tong 2011-03-30
  • 打赏
  • 举报
回复
Send是浮云,发了不一定收的到;发送和接收的代码配合好了才可以
genius_tong 2011-03-30
  • 打赏
  • 举报
回复
没有看到你SendVarData和ReceiveVarData是怎么写的,所以很难说。

我猜是一次发送以后关掉了连接,或者怎滴。另外,不是每次都能收到数据(比如说某一段数据发了以后你要过一会儿才能收到),但是你if (data.Length == 0)就break,这种判断也有可能导致程序中断。

还是看看你那俩函数咋写的吧
加载更多回复(6)

110,552

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧