问题是这样的:
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:未将对象引用设置到对象的实例。
}
}另外,服务端方面,担心短连接因频繁连接和断开影响效能,改为长连接。如一个连接
相应启动一线程,又担心线程开太多影响性能。因此,打算按用户数建Socket连接池,
同时开30个线程,将池中Socket平均分配给30个线程负责,以减少线程数、降低新建线
程和对象的开销、减轻服务器担负,提高用户体验。
大家对这种作法有什么建议和看法?
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:未将对象引用设置到对象的实例。
}
}另外,服务端方面,担心短连接因频繁连接和断开影响效能,改为长连接。如一个连接
相应启动一线程,又担心线程开太多影响性能。因此,打算按用户数建Socket连接池,
同时开30个线程,将池中Socket平均分配给30个线程负责,以减少线程数、降低新建线
程和对象的开销、减轻服务器担负,提高用户体验。
大家对这种作法有什么建议和看法?
解决方案 »
- winfrom 中 statusBar的ICON图标如何动态更改
- ^(0|[1-9][0-9]*)(\.[0-9]{1,3})?$ 求改
- 删除重复记录出错
- 数据库设计:表字段类型为decimal,怎样写存储过程或执行存储过程语句才不会被截断呀?
- 初学,XmlTextReader类操作XML文件的5个问题,1个10分,请教~
- 关于连接数据库的问题,高手请进
- 关于在一个时间段后自动打开某个窗体的问题
- 有什么好的方法做到,dataGrid排序了还是定位到原来的记录里?
- 分辨率的问题
- 如何分区?
- 有人用c#写过kml文件吗,和写xml一样吗,给个建议,谢了!
- 急急急!一点小需求!求简单分析一下!(参与者最少给阳光普照奖)
当有数据的时候才去操作,没有的时候一直循环,但是每次循环都要加适当的休眠
取数据的时候考虑用一个公共队列,
至少是以前是这样用过,没问题