织梦CMS - 轻松建站从此开始!

罗索

浅析:setsockopt()改善程序的健壮性

罗索客 发布于 2006-02-24 14:20 点击:次 
http://topic.csdn.net/t/20041126/20/3592436.html 浅析:setsockopt()改善程序的健壮性 gdy119 (夜风微凉) 2004-11-26 20:02:06 在 VC/MFC / 网络编程 提问 不断的收到coolmei25 (梅生)的答谢,我都不好意思了(我都没帮到他),下面 写出我在网络编程中的一点心得体会
TAG:

http://topic.csdn.net/t/20041126/20/3592436.html

浅析:setsockopt()改善程序的健壮性
gdy119 (夜风微凉)     2004-11-26 20:02:06 在 VC/MFC / 网络编程 提问
不断的收到coolmei25   (梅生)的答谢,我都不好意思了(我都没帮到他),下面
写出我在网络编程中的一点心得体会,希望对他(^_^也对大家)有帮助:
1.   如果在已经处于   ESTABLISHED状态下的socket(一般由端口号和标志符区分)调用
closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:
BOOL   bReuseaddr=TRUE;
setsockopt(s,SOL_SOCKET   ,SO_REUSEADDR,(const   char*)&bReuseaddr,sizeof(BOOL));

2.   如果要已经处于连接状态的soket在调用closesocket后强制关闭,不经历
TIME_WAIT的过程:
BOOL     bDontLinger   =   FALSE;  
setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const   char*)&bDontLinger,sizeof(BOOL));

3.在send(),recv()过程中有时由于网络状况等原因,发收不能预期进行,而设置收发时限:
int   nNetTimeout=1000;//1秒
//发送时限
setsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char   *)&nNetTimeout,sizeof(int));
//接收时限
  setsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char   *)&nNetTimeout,sizeof(int));

4.在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节
(异步);系统默认的状态发送和接收一次为8688字节(约为8.5K);在实际的过程中发送数据
和接收数据量比较大,可以设置socket缓冲区,而避免了send(),recv()不断的循环收发:
//   接收缓冲区
int   nRecvBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const   char*)&nRecvBuf,sizeof(int));
//发送缓冲区
int   nSendBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const   char*)&nSendBuf,sizeof(int));

5.   如果在发送数据的时,希望不经历由系统缓冲区到socket缓冲区的拷贝而影响
程序的性能:
int   nZero=0;
setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char   *)&nZero,sizeof(nZero));

6.同上在recv()完成上述功能(默认情况是将socket缓冲区的内容拷贝到系统缓冲区):
int   nZero=0;
setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char   *)&nZero,sizeof(int));

7.一般在发送UDP数据报的时候,希望该socket发送的数据具有广播特性:
BOOL     bBroadcast=TRUE;  
setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const   char*)&bBroadcast,sizeof(BOOL));

8.在client连接服务器过程中,如果处于非阻塞模式下的socket在connect()的过程中可
以设置connect()延时,直到accpet()被呼叫(本函数设置只有在非阻塞的过程中有显著的
作用,在阻塞的函数调用中作用不大)
BOOL   bConditionalAccept=TRUE;
setsockopt(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,(const   char*)&bConditionalAccept,sizeof(BOOL));

9.如果在发送数据的过程中(send()没有完成,还有数据没发送)而调用了closesocket(),以前我们
一般采取的措施是"从容关闭"shutdown(s,SD_BOTH),但是数据是肯定丢失了,如何设置让程序满足具体
应用的要求(即让没发完的数据发送出去后在关闭socket)?
struct   linger   {
    u_short         l_onoff;
    u_short         l_linger;
};
linger   m_sLinger;
m_sLinger.l_onoff=1;//(在closesocket()调用,但是还有数据没发送完毕的时候容许逗留)
//   如果m_sLinger.l_onoff=0;则功能和2.)作用相同;
m_sLinger.l_linger=5;//(容许逗留的时间为5秒)
setsockopt(s,SOL_SOCKET,SO_LINGER,(const   char*)&m_sLinger,sizeof(linger));
Note:1.在设置了逗留延时,用于一个非阻塞的socket是作用不大的,最好不用;
          2.如果想要程序不经历SO_LINGER需要设置SO_DONTLINGER,或者设置l_onoff=0;

10.还一个用的比较少的是在SDI或者是Dialog的程序中,可以记录socket的调试信息:
(前不久做过这个函数的测试,调式信息可以保存,包括socket建立时候的参数,采用的
具体协议,以及出错的代码都可以记录下来)
BOOL   bDebug=TRUE;
setsockopt(s,SOL_SOCKET,SO_DEBUG,(const   char*)&bDebug,sizeof(BOOL));

11.附加:往往通过setsockopt()设置了缓冲区大小,但还不能满足数据的传输需求,
我的习惯是自己写个处理网络缓冲的类,动态分配内存;下面我将这个类写出,希望对
初学者有所帮助:

//仿照String     改写而成
//==============================================================================
//   二进制数据,主要用于收发网络缓冲区的数据
//   CNetIOBuffer   以   MFC   类   CString   的源代码作为蓝本改写而成,用法与   CString   类似,
//   但是   CNetIOBuffer   中存放的是纯粹的二进制数据,'\\0'   并不作为它的结束标志。
//   其数据长度可以通过   GetLength()   获得,缓冲区地址可以通过运算符   LPBYTE   获得。


//==============================================================================
//     Copyright   (c)   All-Vision   Corporation.   All   rights   reserved.
//     Module:     NetObject
//     file:         SimpleIOBuffer.h
//     Author:     gdy119
//     Email   :     8751webmaster@126.com
//     Date:       2004.11.26
//==============================================================================
//   NetIOBuffer.h
#ifndef   _NETIOBUFFER_H
#define   _NETIOBUFFER_H
//=============================================================================
#define     MAX_BUFFER_LENGTH     1024*1024
//=============================================================================
//主要用来处理网络缓冲的数据
class     CNetIOBuffer    
{
protected:
LPBYTE                             m_pbinData;
int                                   m_nLength;
int                                   m_nTotalLength;
CRITICAL_SECTION m_cs;
        void     Initvalibers();
public:
CNetIOBuffer();
CNetIOBuffer(const   LPBYTE   lbbyte,   int   nLength);
CNetIOBuffer(const   CNetIOBuffer&binarySrc);
virtual   ~CNetIOBuffer();
//=============================================================================
BOOL             CopyData(const   LPBYTE   lbbyte,   int   nLength);
BOOL             ConcatData(const   LPBYTE   lbbyte,   int   nLength);
void             ResetIoBuffer();
int               GetLength()   const;
BOOL             SetLength(int   nLen);
LPBYTE           GetCurPos();
int               GetRemainLen();
BOOL             IsEmpty()   const;
operator       LPBYTE()   const;
static         GetMaxLength()   {   return   MAX_BUFFER_LENGTH;   }
const   CNetIOBuffer&   operator=(const   CNetIOBuffer&   buffSrc);
};
#endif   //  
//   NetOBuffer.cpp:   implementation   of   the   CNetIOBuffer   class.
//======================================================================
#include   "stdafx.h"
#include   "NetIOBuffer.h"
//======================================================================
//=======================================================================
//   Construction/Destruction
CNetIOBuffer::CNetIOBuffer()
{
Initvalibers();

}
CNetIOBuffer::CNetIOBuffer(const   LPBYTE   lbbyte,   int   nLength)
{
Initvalibers();
CopyData(lbbyte,   nLength);
}
CNetIOBuffer::~CNetIOBuffer()
{
delete   []m_pbinData;
      m_pbinData=NULL;
      DeleteCriticalSection(&m_cs);

}
CNetIOBuffer::CNetIOBuffer(const   CNetIOBuffer&binarySrc)
{

      Initvalibers();
      CopyData(binarySrc,binarySrc.GetLength());

}
void   CNetIOBuffer::Initvalibers()
{

m_pbinData           =   NULL;
m_nLength             =   0;
m_nTotalLength   =   MAX_BUFFER_LENGTH;
if(m_pbinData==NULL)
{
m_pbinData=new   BYTE[m_nTotalLength];
ASSERT(m_pbinData!=NULL);
}
InitializeCriticalSection(&m_cs);
}
void   CNetIOBuffer::ResetIoBuffer()
{
EnterCriticalSection(&m_cs);
m_nLength   =   0;
memset(m_pbinData,0,m_nTotalLength);
LeaveCriticalSection(&m_cs);
}

BOOL   CNetIOBuffer::CopyData(const   LPBYTE   lbbyte,   int   nLength)
{
if(   nLength   >   MAX_BUFFER_LENGTH   )
return   FALSE;

ResetIoBuffer();
EnterCriticalSection(&m_cs);
memcpy(m_pbinData,   lbbyte,   nLength   );
m_nLength   =   nLength;
LeaveCriticalSection(&m_cs);

return   TRUE;
}

BOOL   CNetIOBuffer::ConcatData(const   LPBYTE   lbbyte,   int   nLength)
{
if(   m_nLength   +   nLength   >   MAX_BUFFER_LENGTH   )
return   FALSE;

EnterCriticalSection(&m_cs);
memcpy(m_pbinData+m_nLength,   lbbyte,   nLength   );
m_nLength   +=   nLength;
LeaveCriticalSection(&m_cs);

return   TRUE;
}

int   CNetIOBuffer::GetLength()   const
{
return   m_nLength;
}

BOOL   CNetIOBuffer::SetLength(int   nLen)
{
if(   nLen   >   MAX_BUFFER_LENGTH   )
return   FALSE;

EnterCriticalSection(&m_cs);
m_nLength   =   nLen;
LeaveCriticalSection(&m_cs);

return   TRUE;
}

LPBYTE   CNetIOBuffer::GetCurPos()
{

if(   m_nLength   <   MAX_BUFFER_LENGTH   )

return   (m_pbinData+m_nLength);

else
return   NULL;
}

CNetIOBuffer::operator   LPBYTE()   const
{
return   m_pbinData;
}

int   CNetIOBuffer::GetRemainLen()
{

    return   MAX_BUFFER_LENGTH   -   m_nLength;

}
BOOL   CNetIOBuffer::IsEmpty()   const
{
return   m_nLength   ==   0;
}

const   CNetIOBuffer&   CNetIOBuffer::operator=(const   CNetIOBuffer&   buffSrc)
{
if(&buffSrc!=this)
{
CopyData(buffSrc,   buffSrc.GetLength());

}
    return   *this;

}
(夜风微凉)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/200602/495.html]
本文出处: 作者:夜风微凉
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容