Socket:如何使用多个线程分别实现读取、打包、异步发送二进制数据
问题是这样的:
Socket客户端方面,偶用3个线程,分别是
1、Write():读取二进制文件、
2、Packet():打包缓冲区待发数据、
3、Send():发送缓冲区已打包数据。
自定义bufferManager类使用了lock和Monitor来控制线程的状态。
用Stream类辅助复制本地文件来测试bufferManager类准确无误,
说明bufferManager类没有问题,但是把写文件代码改为Socket
异步发送数据时,问题就来了,因为sendCallback(IAsyncResult ar)并不受
bufferManager类中的lock和Monitor来控制,不停地发送,
很快其速度就超过了读取和打包的速度,导致错误:
“NullReferenceException:未将对象引用设置到对象的实例”
请各位出手相助,如何解决这个问题?
部分代码如下:
private void Write(){ // 将二进制数据写入缓冲区bufferManager}private void Packet(){ // 将缓冲区bufferManager中的待发数据打包(添加自定义协议)}private void Send()// 将缓冲区bufferManager中已打包数据异步发送{ Socket handler = _session.ClientSocket; //从缓冲区中循环读取 //while(sentSize<fileSize) //{ byte[] data = bufferManager.GetSendBuffer(); int sSize = data.Length;//实际应该取数据有效长度,这里简单使用data.Length只为代码清晰易读 if(sSize>0) { //测试bufferManager类时,这里用Stream类来将数据写盘 handler.BeginSend(data, 0, data.Length, SocketFlags.None, //开始异步发送 new AsyncCallback(sendCallback), handler); } sentSize += sSize; //} //bufferManager.SentDone = true;}/// <summary>/// 异步发送回调函数/// </summary>/// <param name="ar">包含要发送的数据流及数据包的包头</param>private void sendCallback(IAsyncResult ar){ try { Socket socket = (Socket)ar.AsyncState; //得到包含Socket的对象 int sent = socket.EndSend(ar); if(sentSize<fileSize)//sentSize:已发送文件的字节数;fileSize:发送文件的字节长度 { byte[] data = bufferManager.GetSendBuffer(); int sSize = data.Length;//实际应该取数据有效长度,这里简单使用data.Length只为代码清晰易读 if(sSize>0) { socket.BeginSend(data, 0, data.Length, SocketFlags.None, //开始异步发送 new AsyncCallback(sendCallback), socket); } sentSize += sSize; } else { bufferManager.SentDone = true; } } catch(Exception ex)//NullReferenceException { //NullReferenceException:未将对象引用设置到对象的实例。 }}