C# Socket 一个客户端对应多台设备接收数据问题 socket测试数据 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 你上面写的是只是客户端服务端的 http://www.cnblogs.com/congblog/archive/2012/03/26/2418804.html方法有多种,eventHandle.WaitOne()不是必须的,根据你的需求来 您误解我的意思了 ,我不需要去编写C# Soclet服务端的代码。是多台设备的模式为服务端,然后发送数据,我实现C# socket客户端去接收多台设备的数据,不需要双向通信。我只需要负责收就可以了。您看看我的代码 如何才能实现,连接成功一台设备 就开始接收一台的数据。 我现在代码有问题。只能接收一台 连接了第一台后 Console.Read(); 这样就停住了,需要按回车才能继续啊 谢谢回答,还有一个问题 麻烦了,看您知道不 var socket = ar.AsyncState as Socket; var length = socket.EndReceive(ar); //分多次接收 byte[] reallData = new byte[length]; Array.Copy(buffer, reallData, reallData.Length); string data = BitConverter.ToString(reallData) + "\r\n"; StatisticsData(data);我的一台设备由于数据量比较大,可能一次的数据收取过来的时候,是分了4次左右发送的那么 var length = socket.EndReceive(ar);这个地方接收的时候 我看了一下 最大是1024我这里该如何确保一次接收的数据是一个完整的包?该如何合并或者判断 谢谢~ 为什么我这里用了copy没用呢?我看网上是这样合并的 不要胡乱copy,你这不是每次都给覆盖掉了吗你得记录下每次到底把数据写入数组的哪里到哪里了,下次从后面继续往里写,同时累加总数据长度或者把byte[]改为List<byte> 属于不同连接的数据没有区分开啊,应该定义一个数据结构来存储, 然后在 BeginReceive 的最后一个参数传递.用 ar.AsyncState 取出.不然共用一个buffer数据都混了.数据结构至少应包含 Socket,buffer,reallData 等. 就是这样做的,来区分每一台设备发送的数据,只不过每台发送过来的数据量 不能一次接收完整。以下是完整代码 异步函数中的 /// <summary> /// 异步接收数据 /// </summary> /// <param name="ar"></param> public static void ReceiveMessage(IAsyncResult ar) { try { var socket = ar.AsyncState as Socket; var length = socket.EndReceive(ar); //分多次接收 byte[] reallData = new byte[length]; //Array.Copy(buffer, reallData, reallData.Length); string data = BitConverter.ToString(reallData) + "\r\n"; StatisticsData(data); //接收下一个消息(因为这是一个递归的调用,所以这样就可以一直接收消息了) socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket); } catch (Exception ex) { Console.WriteLine(ex.Message); } } 你看看你的实例是在哪里创建的???仔细看看,一循环可就全没了。万幸的是,你的这个foreach 循环根本无法实现,因为foreach 一执行就处于无限的异步委托循环,所以只能接收第一个连接的数据,否则你如果没有下面的异步委托,恐怕你循环出的所有实例全都丢了。你没有别的路可走,唯有委托事件才能实现。 前辈,咱一步一步来,我们先不纠结循环的事情,现在咱就当一台设备在工作。设备是Server端,我程序作为客户端去接收设备数据,现在我设备接收到了数据,如何确设备数据的完整性,就像我上面描述的,因为设备一次发送的数据量大了,所以分了几次发送。我该在异步函数中如何接收,代码如何修改,这是我现在要解决的问题。至于程序去接收多台设备的问题,先放一边。不好意思啊。这个东西我刚接触,您说的对。我就算今天不吃不喝也得搞懂它 但就这一行而言,你要同时连上多个设备,不能在循环中阻塞!大致应该写 static List<Socket> cs = new List<Socket>(); static void Main(string[] args) { //创建一个Socket foreach (Address addressValue in GetAddress()) { socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); cs.Add(socket); try { socket.Connect(addressValue.IP, addressValue.Port); Console.WriteLine("{0}:{1}:Conneted...." + "\r\n", addressValue.IP, addressValue.Port); //实现接受消息的方法 socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket); } catch (Exception ex) { Console.WriteLine(ex.Message); } } Console.WriteLine("....................按任意键结束"); Console.Read(); } 既然使用了TCP方式,必须假定不能一次性收全数据包的,这个处理不能省略,因此数据包的开头,结尾标识至少需要其一.在循环中buffer都没有初始化,那就是共用同一个,问题很严重.多次接收必然要用一个地方保存,通常用MemoryStream不限制容量. 肯刻苦钻研是好事。但也别太钻牛角尖,否则太耽误时间,还不一定解决问题。针对你的问题,你这里//Array.Copy(buffer, reallData, reallData.Length);这句显得一点意义都没有。如果想实现真正的分包发送,你要在数据进入异步发送前分割,然后把段数据加入一个序号标记,然后放入一个循环中,分别进行异步发送。接收端接收得到的是多段数据,将其存入内存或者本地文件,再提取每段数据的标记,按照序号进行连接。这就非常复杂了。修改方案如下:上面那句多余的话代码去掉即可。buffer 这个缓冲区在 BeginReceive 的异步操作当中,会自动按照你设置的缓冲区大小分段读取数据,直到数据读取完成执行委托的回调函数。你在委托函数里得到的数据就是已经分段读取并合完成后的数据,由于你采用tcp连接,根本无需担心数据传输错误丢包问题,除非是网络中断,无法连接了。 不知道你服务端发送的数据有多大,如果有几百兆甚至几个G,那么着实需要分段发送来缩短传送时间。 如果数据量不是很大,就算几十M对于TCP连接来说,数据的传输稳定性是不用担心的。现在你的服务器发送数据情况来看,分段并放入循环去异步发送数据,一是发送的每段的顺序和接收顺序你无法保证,容易导致拼接时数据错误无法使用。所以建议发送的数据尽量一次性完成而在接收方采用缓冲区分段接收。如果非要分段发送,你必须把服务端每段发送的数据都要做文件名和顺序标记,否则接收方无法判断接收到的是什么东西,或者使用时间戳进行标记,加上发送一个额外的连接数据包,记录所有分段的时间戳,服务端接收数据时实时去连接包中去验证,直到所有数据都接受完成再进行数据连接。你可要知道,你一旦分段发送数据,在接收方每次异步接收到的数据之间将不再有任何联系,你必须人为的根据一个验证规则去识别哪些接收到的数据其实应该组合在一起。而且必须要同时接收一个验证规则去连接想要连接的数据。如果没有规则,接收端会胡乱的去合并数据的。 多个设备 往你的 Socket 发送数据;你的 Socket 只接收;—— 那么,你的 Socket 就是一个 服务端角色嘛。—————————————————————————————— 实在不行的话,就用 WebService 吧。之前,用 WebService 传输过 3G 的电影文件 —— 速度 一点不比 Socket 慢。 C# visio二次开发开发中 如何实现排列下属图形布局? Zedgraph问题 c#关闭最小化到托盘区和tabcontrol控件 vc与asp.net之间的通信 求access导入oracle数据库程序!急急!!! vs2005 c#中timer这个控件如何使用 问一个关于窗体关闭按钮的超难问题 高分求解:问个有关快捷键设计标准的问题 c#webbrower控件调用地图技术 关于dataset与内存消耗问题! 关于CodeSmith的问题 在while循环里给lable动态赋值,显示出lable值得变化。
服务端的 http://www.cnblogs.com/congblog/archive/2012/03/26/2418804.html
方法有多种,eventHandle.WaitOne()不是必须的,根据你的需求来
您误解我的意思了 ,我不需要去编写C# Soclet服务端的代码。是多台设备的模式为服务端,然后发送数据,我实现C# socket客户端去接收多台设备的数据,不需要双向通信。我只需要负责收就可以了。您看看我的代码 如何才能实现,连接成功一台设备 就开始接收一台的数据。 我现在代码有问题。只能接收一台
谢谢回答,还有一个问题 麻烦了,看您知道不
var socket = ar.AsyncState as Socket;
var length = socket.EndReceive(ar); //分多次接收
byte[] reallData = new byte[length];
Array.Copy(buffer, reallData, reallData.Length);
string data = BitConverter.ToString(reallData) + "\r\n"; StatisticsData(data);我的一台设备由于数据量比较大,可能一次的数据收取过来的时候,是分了4次左右发送的
那么 var length = socket.EndReceive(ar);这个地方接收的时候 我看了一下 最大是1024
我这里该如何确保一次接收的数据是一个完整的包?该如何合并或者判断 谢谢~
为什么我这里用了copy没用呢?我看网上是这样合并的
你得记录下每次到底把数据写入数组的哪里到哪里了,下次从后面继续往里写,同时累加总数据长度
或者把byte[]改为List<byte>
就是这样做的,来区分每一台设备发送的数据,只不过每台发送过来的数据量 不能一次接收完整。以下是完整代码 异步函数中的 /// <summary>
/// 异步接收数据
/// </summary>
/// <param name="ar"></param>
public static void ReceiveMessage(IAsyncResult ar)
{
try
{
var socket = ar.AsyncState as Socket; var length = socket.EndReceive(ar); //分多次接收
byte[] reallData = new byte[length];
//Array.Copy(buffer, reallData, reallData.Length);
string data = BitConverter.ToString(reallData) + "\r\n"; StatisticsData(data); //接收下一个消息(因为这是一个递归的调用,所以这样就可以一直接收消息了)
socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
前辈,咱一步一步来,我们先不纠结循环的事情,现在咱就当一台设备在工作。
设备是Server端,我程序作为客户端去接收设备数据,现在我设备接收到了数据,如何确设备数据的完整性,就像我上面描述的,因为设备一次发送的数据量大了,所以分了几次发送。我该在异步函数中如何接收,代码如何修改,这是我现在要解决的问题。至于程序去接收多台设备的问题,先放一边。不好意思啊。这个东西我刚接触,您说的对。我就算今天不吃不喝也得搞懂它
static List<Socket> cs = new List<Socket>(); static void Main(string[] args)
{
//创建一个Socket
foreach (Address addressValue in GetAddress())
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
cs.Add(socket);
try
{
socket.Connect(addressValue.IP, addressValue.Port);
Console.WriteLine("{0}:{1}:Conneted...." + "\r\n", addressValue.IP, addressValue.Port);
//实现接受消息的方法
socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Console.WriteLine("....................按任意键结束");
Console.Read();
}
在循环中buffer都没有初始化,那就是共用同一个,问题很严重.
多次接收必然要用一个地方保存,通常用MemoryStream不限制容量.
buffer 这个缓冲区在 BeginReceive 的异步操作当中,会自动按照你设置的缓冲区大小分段读取数据,直到数据读取完成执行委托的回调函数。你在委托函数里得到的数据就是已经分段读取并合完成后的数据,由于你采用tcp连接,根本无需担心数据传输错误丢包问题,除非是网络中断,无法连接了。
如果数据量不是很大,就算几十M对于TCP连接来说,数据的传输稳定性是不用担心的。现在你的服务器发送数据情况来看,分段并放入循环去异步发送数据,一是发送的每段的顺序和接收顺序你无法保证,容易导致拼接时数据错误无法使用。所以建议发送的数据尽量一次性完成而在接收方采用缓冲区分段接收。如果非要分段发送,你必须把服务端每段发送的数据都要做文件名和顺序标记,否则接收方无法判断接收到的是什么东西,或者使用时间戳进行标记,加上发送一个额外的连接数据包,记录所有分段的时间戳,服务端接收数据时实时去连接包中去验证,直到所有数据都接受完成再进行数据连接。你可要知道,你一旦分段发送数据,在接收方每次异步接收到的数据之间将不再有任何联系,你必须人为的根据一个验证规则去识别哪些接收到的数据其实应该组合在一起。而且必须要同时接收一个验证规则去连接想要连接的数据。如果没有规则,接收端会胡乱的去合并数据的。
你的 Socket 只接收;—— 那么,你的 Socket 就是一个 服务端角色嘛。
——————————————————————————————
实在不行的话,就用 WebService 吧。之前,用 WebService 传输过 3G 的电影文件 —— 速度 一点不比 Socket 慢。