读书人

Socket:怎么使用多个线程分别实现读取

发布时间: 2012-02-19 19:43:38 作者: rapoo

Socket:如何使用多个线程分别实现读取、打包、异步发送二进制数据
问题是这样的:
Socket客户端方面,偶用3个线程,分别是
1、Write():读取二进制文件、
2、Packet():打包缓冲区待发数据、
3、Send():发送缓冲区已打包数据。
自定义bufferManager类使用了lock和Monitor来控制线程的状态。
用Stream类辅助复制本地文件来测试bufferManager类准确无误,
说明bufferManager类没有问题,但是把写文件代码改为Socket
异步发送数据时,问题就来了,因为sendCallback(IAsyncResult ar)并不受
bufferManager类中的lock和Monitor来控制,不停地发送,
很快其速度就超过了读取和打包的速度,导致错误:
“NullReferenceException:未将对象引用设置到对象的实例”
请各位出手相助,如何解决这个问题?
部分代码如下:

C# code
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个线程负责,以减少线程数、降低新建线
程和对象的开销、减轻服务器担负,提高用户体验。
大家对这种作法有什么建议和看法?

[解决办法]
简单处理方法:sendCallback方法在发送数据之前,判断一下有没有数据,或者判断一下返回的数据是否为null,等于null则什么都不发送,
[解决办法]
将Send()的BeginSend改为Send,这样就好控制了。
[解决办法]
Send完一个包再Send下一个包不行吗,为什么要异步?
[解决办法]
每个线程用一个while,
当有数据的时候才去操作,没有的时候一直循环,但是每次循环都要加适当的休眠
取数据的时候考虑用一个公共队列,
至少是以前是这样用过,没问题

读书人网 >C#

热点推荐