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

主  题: 浅析:setsockopt()改善程序的健壮性
作  者: gdy119 (夜风微凉)
不断的收到coolmei25 (梅生)的答谢,我都不好意思了(我都没帮到他),下面
写出我在网络编程中的一点心得体会,希望对他(^_^也对大家)有帮助:
1. 如果在已经处于 ESTABLISHED状态下的socket(一般由端口号和标志符区分)调用
closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:
BOOL bReuseaddr=TRUE
etsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL))
2. 如果要已经处于连接状态的soket在调用closesocket后强制关闭,不经历
TIME_WAIT的过程:
BOOL bDontLinger = FALSE
etsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL))
3.在send(),recv()过程中有时由于网络状况等原因,发收不能预期进行,而设置收发时限:
int nNetTimeout=1000;//1秒
//发送时限
etsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int))
//接收时限
etsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int))
4.在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节
(异步);系统默认的状态发送和接收一次为8688字节(约为8.5K);在实际的过程中发送数据
和接收数据量比较大,可以设置socket缓冲区,而避免了send(),recv()不断的循环收发:
// 接收缓冲区
int nRecvBuf=32*1024;//设置为32K
etsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int))
//发送缓冲区
int nSendBuf=32*1024;//设置为32K
etsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int))
5. 如果在发送数据的时,希望不经历由系统缓冲区到socket缓冲区的拷贝而影响
程序的性能:
int nZero=0
etsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero))
6.同上在recv()完成上述功能(默认情况是将socket缓冲区的内容拷贝到系统缓冲区):
int nZero=0
etsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nZero,sizeof(int))
7.一般在发送UDP数据报的时候,希望该socket发送的数据具有广播特性:
BOOL bBroadcast=TRUE
etsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(BOOL))
8.在client连接服务器过程中,如果处于非阻塞模式下的socket在connect()的过程中可
以设置connect()延时,直到accpet()被呼叫(本函数设置只有在非阻塞的过程中有显著的
作用,在阻塞的函数调用中作用不大)
BOOL bConditionalAccept=TRUE
etsockopt(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,(const char*)&bConditionalAccept,sizeof(BOOL))
9.如果在发送数据的过程中(send()没有完成,还有数据没发送)而调用了closesocket(),以前我们
一般采取的措施是"从容关闭"shutdown(s,SD_BOTH),但是数据是肯定丢失了,如何设置让程序满足具体
应用的要求(即让没发完的数据发送出去后在关闭socket)?
truct 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秒)
etsockopt(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
etsockopt(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
rotected:
LPBYTE m_pbinData
int m_nLength
int m_nTotalLength
CRITICAL_SECTIONm_c
void Initvalibers()
ublic:
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
tatic 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/Destructio
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 = nLe
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 *thi
回复人: PiggyXP(【小猪】●至爱VC,至爱网络版●) ( ) 信誉:204
其实我觉得第5条很应该值得注意
int nZero=0
etsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero))
记得以前有些朋友讨论过,socket虽然send成功了,但是其实只是发送到数据缓冲区里面了,而并没有真正的在物理设备上发送出去;而通过这条语句,将发送缓冲区设置为0,即屏蔽掉发送缓冲以后,一旦send返回(当然是就阻塞套结字来说),就可以肯定数据已经在发送的途中了^_^,但是这样做也许会影响系统的性能
to:Sander()
UDP也有拷贝过程,但是UDP包有最大限制为64K;
TCP_NODELAY 一般用在the normal data stream 上;
12.发送数据时候一般是系统缓冲区满以后才发送,现在设置为只要系统
缓冲区有数据就立刻发送:
BOOL bNodelay=TRUE
SetSockOpt(s,IPPROTO_TCP,TCP_NODELAY,(const char*)&bNodelayt,sizeof(BOOL))
回复人: od4ys(风风) ( ) 信誉:100
etoptsock()这个函数 设置成端口复用的时候,很容易对一些没有进行单独bind模式的程序造成危害。
比如old的 ping icmp door,简单的sniffer后,收到包,然后设置setoptsock bind web服务,然后建立个cmd进程 bind再80端口
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值